CultriX commited on
Commit
ceed10d
Β·
verified Β·
1 Parent(s): d71e8ea

=== INSTRUCTIONS === Redesign this tool for client-side encryption/decryption of either plain text or file attachments. Improve aesthetics and upgrade available and/or add new features that improve us

Browse files
Files changed (2) hide show
  1. README.md +9 -6
  2. index.html +1052 -19
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Securecrypt Pro Rnxru
3
- emoji: πŸŒ–
4
- colorFrom: green
5
- colorTo: green
6
  sdk: static
7
- pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
1
  ---
2
+ title: SecureCrypt Pro πŸ”
3
+ colorFrom: purple
4
+ colorTo: blue
 
5
  sdk: static
6
+ emoji: 🚧
7
+ tags:
8
+ - deepsite-v4
9
  ---
10
 
11
+ # SecureCrypt Pro πŸ”
12
+
13
+ This project has been created with [DeepSite](https://deepsite.hf.co) AI Vibe Coding.
index.html CHANGED
@@ -1,19 +1,1052 @@
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" class="scroll-smooth">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SecureCrypt | Military-Grade Client-Side Encryption</title>
7
+ <meta name="description" content="Secure client-side encryption for text and files. Zero server storage, AES-256-GCM encryption.">
8
+
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+ <script src="https://unpkg.com/lucide@latest"></script>
11
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
12
+
13
+ <script>
14
+ tailwind.config = {
15
+ darkMode: 'class',
16
+ theme: {
17
+ extend: {
18
+ fontFamily: {
19
+ sans: ['Inter', 'sans-serif'],
20
+ mono: ['JetBrains Mono', 'monospace'],
21
+ },
22
+ colors: {
23
+ primary: {
24
+ 50: '#eff6ff',
25
+ 100: '#dbeafe',
26
+ 500: '#3b82f6',
27
+ 600: '#2563eb',
28
+ 700: '#1d4ed8',
29
+ 900: '#1e3a8a',
30
+ },
31
+ crypto: {
32
+ encrypt: '#10b981',
33
+ decrypt: '#f59e0b',
34
+ danger: '#ef4444',
35
+ }
36
+ },
37
+ animation: {
38
+ 'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite',
39
+ 'float': 'float 6s ease-in-out infinite',
40
+ 'shimmer': 'shimmer 2s linear infinite',
41
+ },
42
+ keyframes: {
43
+ float: {
44
+ '0%, 100%': { transform: 'translateY(0)' },
45
+ '50%': { transform: 'translateY(-10px)' },
46
+ },
47
+ shimmer: {
48
+ '0%': { backgroundPosition: '-1000px 0' },
49
+ '100%': { backgroundPosition: '1000px 0' },
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ </script>
56
+
57
+ <style>
58
+ .glass-panel {
59
+ background: rgba(255, 255, 255, 0.05);
60
+ backdrop-filter: blur(10px);
61
+ border: 1px solid rgba(255, 255, 255, 0.1);
62
+ }
63
+
64
+ .dark .glass-panel {
65
+ background: rgba(17, 24, 39, 0.7);
66
+ border: 1px solid rgba(255, 255, 255, 0.05);
67
+ }
68
+
69
+ .gradient-text {
70
+ background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%);
71
+ -webkit-background-clip: text;
72
+ -webkit-text-fill-color: transparent;
73
+ background-clip: text;
74
+ }
75
+
76
+ .security-grid {
77
+ background-image: radial-gradient(circle at 1px 1px, rgba(59, 130, 246, 0.15) 1px, transparent 0);
78
+ background-size: 20px 20px;
79
+ }
80
+
81
+ .drop-zone {
82
+ transition: all 0.3s ease;
83
+ }
84
+
85
+ .drop-zone.drag-over {
86
+ border-color: #3b82f6;
87
+ background: rgba(59, 130, 246, 0.1);
88
+ transform: scale(1.02);
89
+ }
90
+
91
+ .tab-active {
92
+ background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
93
+ color: white;
94
+ }
95
+
96
+ .strength-weak { background: #ef4444; }
97
+ .strength-fair { background: #f59e0b; }
98
+ .strength-good { background: #3b82f6; }
99
+ .strength-strong { background: #10b981; }
100
+
101
+ .toast {
102
+ animation: slideIn 0.3s ease-out;
103
+ }
104
+
105
+ @keyframes slideIn {
106
+ from { transform: translateX(100%); opacity: 0; }
107
+ to { transform: translateX(0); opacity: 1; }
108
+ }
109
+
110
+ .encrypt-mode { border-color: #10b981; }
111
+ .decrypt-mode { border-color: #f59e0b; }
112
+ </style>
113
+ </head>
114
+ <body class="bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-gray-100 transition-colors duration-300 font-sans">
115
+
116
+ <!-- Navigation -->
117
+ <nav class="fixed w-full z-50 glass-panel border-b border-gray-200 dark:border-gray-800">
118
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
119
+ <div class="flex justify-between h-16 items-center">
120
+ <div class="flex items-center space-x-3">
121
+ <div class="w-10 h-10 bg-gradient-to-br from-blue-500 to-purple-600 rounded-xl flex items-center justify-center shadow-lg">
122
+ <i data-lucide="shield-check" class="w-6 h-6 text-white"></i>
123
+ </div>
124
+ <span class="text-xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
125
+ SecureCrypt
126
+ </span>
127
+ </div>
128
+
129
+ <div class="flex items-center space-x-4">
130
+ <button onclick="toggleTheme()" class="p-2 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-800 transition-colors">
131
+ <i data-lucide="sun" class="w-5 h-5 hidden dark:block"></i>
132
+ <i data-lucide="moon" class="w-5 h-5 block dark:hidden"></i>
133
+ </button>
134
+ <a href="#security" class="hidden md:block text-sm font-medium hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
135
+ Security Specs
136
+ </a>
137
+ <div class="flex items-center space-x-2 px-3 py-1 rounded-full bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400 text-xs font-semibold">
138
+ <span class="w-2 h-2 bg-green-500 rounded-full animate-pulse"></span>
139
+ <span>Client-Side Only</span>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ </nav>
145
+
146
+ <!-- Hero Section -->
147
+ <section class="pt-32 pb-16 px-4 sm:px-6 lg:px-8 relative overflow-hidden">
148
+ <div class="absolute inset-0 security-grid opacity-50"></div>
149
+ <div class="absolute top-0 left-1/2 -translate-x-1/2 w-full h-96 bg-gradient-to-b from-blue-500/10 to-transparent pointer-events-none"></div>
150
+
151
+ <div class="max-w-4xl mx-auto text-center relative z-10">
152
+ <div class="inline-flex items-center space-x-2 px-4 py-2 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 text-sm font-medium mb-6 animate-float">
153
+ <i data-lucide="lock" class="w-4 h-4"></i>
154
+ <span>Military-Grade AES-256-GCM Encryption</span>
155
+ </div>
156
+
157
+ <h1 class="text-5xl md:text-6xl font-bold mb-6 leading-tight">
158
+ Encrypt Your Data <br>
159
+ <span class="gradient-text">In the Browser</span>
160
+ </h1>
161
+
162
+ <p class="text-xl text-gray-600 dark:text-gray-400 mb-8 max-w-2xl mx-auto">
163
+ Zero server storage. Zero data transmission. Your files and text never leave your device.
164
+ Open-source, auditable, and completely private.
165
+ </p>
166
+
167
+ <div class="flex flex-wrap justify-center gap-4 text-sm text-gray-500 dark:text-gray-400">
168
+ <div class="flex items-center space-x-2">
169
+ <i data-lucide="check-circle" class="w-4 h-4 text-green-500"></i>
170
+ <span>AES-256-GCM</span>
171
+ </div>
172
+ <div class="flex items-center space-x-2">
173
+ <i data-lucide="check-circle" class="w-4 h-4 text-green-500"></i>
174
+ <span>PBKDF2 600k Iterations</span>
175
+ </div>
176
+ <div class="flex items-center space-x-2">
177
+ <i data-lucide="check-circle" class="w-4 h-4 text-green-500"></i>
178
+ <span>Open Source</span>
179
+ </div>
180
+ </div>
181
+ </div>
182
+ </section>
183
+
184
+ <!-- Main Application -->
185
+ <section class="pb-20 px-4 sm:px-6 lg:px-8">
186
+ <div class="max-w-6xl mx-auto">
187
+
188
+ <!-- Mode Tabs -->
189
+ <div class="flex justify-center mb-8">
190
+ <div class="bg-white dark:bg-gray-800 p-1 rounded-2xl shadow-lg border border-gray-200 dark:border-gray-700 inline-flex">
191
+ <button onclick="switchMode('text')" id="tab-text" class="tab-active px-6 py-3 rounded-xl font-medium transition-all duration-200 flex items-center space-x-2">
192
+ <i data-lucide="type" class="w-4 h-4"></i>
193
+ <span>Text</span>
194
+ </button>
195
+ <button onclick="switchMode('file')" id="tab-file" class="px-6 py-3 rounded-xl font-medium transition-all duration-200 flex items-center space-x-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200">
196
+ <i data-lucide="file-up" class="w-4 h-4"></i>
197
+ <span>File</span>
198
+ </button>
199
+ </div>
200
+ </div>
201
+
202
+ <!-- Operation Toggle -->
203
+ <div class="flex justify-center mb-8">
204
+ <div class="bg-gray-100 dark:bg-gray-800 p-1 rounded-full inline-flex relative">
205
+ <div id="operation-indicator" class="absolute left-1 top-1 w-[calc(50%-4px)] h-[calc(100%-8px)] bg-white dark:bg-gray-700 rounded-full shadow-md transition-all duration-300"></div>
206
+ <button onclick="setOperation('encrypt')" class="relative z-10 px-8 py-2 rounded-full font-medium transition-colors duration-200 flex items-center space-x-2" id="btn-encrypt">
207
+ <i data-lucide="lock" class="w-4 h-4"></i>
208
+ <span>Encrypt</span>
209
+ </button>
210
+ <button onclick="setOperation('decrypt')" class="relative z-10 px-8 py-2 rounded-full font-medium transition-colors duration-200 flex items-center space-x-2 text-gray-600 dark:text-gray-400" id="btn-decrypt">
211
+ <i data-lucide="unlock" class="w-4 h-4"></i>
212
+ <span>Decrypt</span>
213
+ </button>
214
+ </div>
215
+ </div>
216
+
217
+ <!-- Text Mode Interface -->
218
+ <div id="interface-text" class="glass-panel rounded-3xl p-8 shadow-2xl border border-gray-200 dark:border-gray-700">
219
+ <div class="grid md:grid-cols-2 gap-6">
220
+
221
+ <!-- Input Section -->
222
+ <div class="space-y-4">
223
+ <div class="flex justify-between items-center">
224
+ <label class="text-sm font-semibold text-gray-700 dark:text-gray-300 flex items-center space-x-2">
225
+ <i data-lucide="edit-3" class="w-4 h-4"></i>
226
+ <span>Input</span>
227
+ </label>
228
+ <button onclick="clearText()" class="text-xs text-gray-500 hover:text-red-500 transition-colors">
229
+ Clear
230
+ </button>
231
+ </div>
232
+
233
+ <div class="relative">
234
+ <textarea
235
+ id="text-input"
236
+ placeholder="Enter text to encrypt or encrypted data to decrypt..."
237
+ class="w-full h-64 p-4 rounded-xl bg-gray-50 dark:bg-gray-900 border-2 border-gray-200 dark:border-gray-700 focus:border-blue-500 focus:ring-0 resize-none transition-all font-mono text-sm"
238
+ ></textarea>
239
+ <div class="absolute bottom-4 right-4 text-xs text-gray-400" id="char-count">0 chars</div>
240
+ </div>
241
+ </div>
242
+
243
+ <!-- Output Section -->
244
+ <div class="space-y-4">
245
+ <div class="flex justify-between items-center">
246
+ <label class="text-sm font-semibold text-gray-700 dark:text-gray-300 flex items-center space-x-2">
247
+ <i data-lucide="shield" class="w-4 h-4"></i>
248
+ <span>Result</span>
249
+ </label>
250
+ <div class="flex space-x-2">
251
+ <button onclick="copyOutput()" class="p-2 rounded-lg bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors" title="Copy to clipboard">
252
+ <i data-lucide="copy" class="w-4 h-4"></i>
253
+ </button>
254
+ <button onclick="downloadOutput()" class="p-2 rounded-lg bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors" title="Download as file">
255
+ <i data-lucide="download" class="w-4 h-4"></i>
256
+ </button>
257
+ </div>
258
+ </div>
259
+
260
+ <div class="relative">
261
+ <textarea
262
+ id="text-output"
263
+ readonly
264
+ placeholder="Result will appear here..."
265
+ class="w-full h-64 p-4 rounded-xl bg-gray-100 dark:bg-gray-800/50 border-2 border-gray-200 dark:border-gray-700 resize-none font-mono text-sm text-gray-600 dark:text-gray-400"
266
+ ></textarea>
267
+ <div id="output-overlay" class="absolute inset-0 flex items-center justify-center bg-gray-900/5 dark:bg-gray-900/20 rounded-xl backdrop-blur-sm hidden">
268
+ <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
269
+ </div>
270
+ </div>
271
+ </div>
272
+ </div>
273
+
274
+ <!-- Password Section -->
275
+ <div class="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
276
+ <div class="flex flex-col md:flex-row gap-4">
277
+ <div class="flex-1 relative">
278
+ <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
279
+ Password / Passphrase
280
+ </label>
281
+ <div class="relative">
282
+ <input
283
+ type="password"
284
+ id="password-input"
285
+ placeholder="Enter strong password..."
286
+ class="w-full px-4 py-3 rounded-xl bg-gray-50 dark:bg-gray-900 border-2 border-gray-200 dark:border-gray-700 focus:border-blue-500 focus:ring-0 transition-all pr-24"
287
+ oninput="checkPasswordStrength()"
288
+ >
289
+ <button onclick="togglePasswordVisibility()" class="absolute right-12 top-1/2 -translate-y-1/2 p-2 text-gray-400 hover:text-gray-600">
290
+ <i data-lucide="eye" class="w-4 h-4" id="eye-icon"></i>
291
+ </button>
292
+ <button onclick="generatePassword()" class="absolute right-2 top-1/2 -translate-y-1/2 p-2 text-blue-500 hover:text-blue-700" title="Generate secure password">
293
+ <i data-lucide="refresh-cw" class="w-4 h-4"></i>
294
+ </button>
295
+ </div>
296
+
297
+ <!-- Password Strength -->
298
+ <div class="mt-2 flex items-center space-x-2">
299
+ <div class="flex-1 h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
300
+ <div id="strength-bar" class="h-full w-0 transition-all duration-300 strength-weak"></div>
301
+ </div>
302
+ <span id="strength-text" class="text-xs font-medium text-gray-500">Empty</span>
303
+ </div>
304
+ </div>
305
+
306
+ <div class="flex items-end">
307
+ <button onclick="processText()" id="action-btn" class="w-full md:w-auto px-8 py-3 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white font-semibold rounded-xl shadow-lg transform hover:scale-105 transition-all flex items-center justify-center space-x-2 min-w-[160px]">
308
+ <i data-lucide="lock" class="w-5 h-5" id="action-icon"></i>
309
+ <span id="action-text">Encrypt</span>
310
+ </button>
311
+ </div>
312
+ </div>
313
+ </div>
314
+ </div>
315
+
316
+ <!-- File Mode Interface -->
317
+ <div id="interface-file" class="hidden glass-panel rounded-3xl p-8 shadow-2xl border border-gray-200 dark:border-gray-700">
318
+
319
+ <!-- File Drop Zone -->
320
+ <div
321
+ id="drop-zone"
322
+ class="drop-zone border-3 border-dashed border-gray-300 dark:border-gray-600 rounded-2xl p-12 text-center cursor-pointer hover:border-blue-500 transition-all"
323
+ onclick="document.getElementById('file-input').click()"
324
+ ondrop="handleDrop(event)"
325
+ ondragover="handleDragOver(event)"
326
+ ondragleave="handleDragLeave(event)"
327
+ >
328
+ <input type="file" id="file-input" class="hidden" onchange="handleFileSelect(event)">
329
+
330
+ <div class="w-20 h-20 mx-auto mb-4 rounded-full bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center">
331
+ <i data-lucide="upload-cloud" class="w-10 h-10 text-blue-600 dark:text-blue-400"></i>
332
+ </div>
333
+
334
+ <h3 class="text-lg font-semibold mb-2">Drop your file here</h3>
335
+ <p class="text-gray-500 dark:text-gray-400 mb-4">or click to browse (Max 10MB)</p>
336
+
337
+ <div id="file-info" class="hidden mt-4 p-4 bg-gray-50 dark:bg-gray-800 rounded-xl inline-flex items-center space-x-3">
338
+ <i data-lucide="file" class="w-8 h-8 text-blue-500"></i>
339
+ <div class="text-left">
340
+ <div id="file-name" class="font-medium">filename.txt</div>
341
+ <div id="file-size" class="text-sm text-gray-500">0 KB</div>
342
+ </div>
343
+ <button onclick="clearFile(event)" class="p-1 hover:bg-gray-200 dark:hover:bg-gray-700 rounded">
344
+ <i data-lucide="x" class="w-4 h-4"></i>
345
+ </button>
346
+ </div>
347
+ </div>
348
+
349
+ <!-- File Password & Action -->
350
+ <div class="mt-6 grid md:grid-cols-2 gap-6">
351
+ <div>
352
+ <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
353
+ Password Protection
354
+ </label>
355
+ <div class="relative">
356
+ <input
357
+ type="password"
358
+ id="file-password"
359
+ placeholder="Enter password..."
360
+ class="w-full px-4 py-3 rounded-xl bg-gray-50 dark:bg-gray-900 border-2 border-gray-200 dark:border-gray-700 focus:border-blue-500 focus:ring-0 transition-all"
361
+ >
362
+ <button onclick="generateFilePassword()" class="absolute right-3 top-1/2 -translate-y-1/2 text-xs text-blue-500 hover:text-blue-700 font-medium">
363
+ Generate
364
+ </button>
365
+ </div>
366
+ </div>
367
+
368
+ <div class="flex items-end">
369
+ <button onclick="processFile()" id="file-action-btn" class="w-full px-8 py-3 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white font-semibold rounded-xl shadow-lg transform hover:scale-105 transition-all flex items-center justify-center space-x-2 disabled:opacity-50 disabled:cursor-not-allowed" disabled>
370
+ <i data-lucide="lock" class="w-5 h-5"></i>
371
+ <span>Encrypt File</span>
372
+ </button>
373
+ </div>
374
+ </div>
375
+
376
+ <!-- Progress Bar -->
377
+ <div id="progress-container" class="hidden mt-6">
378
+ <div class="flex justify-between text-sm mb-2">
379
+ <span class="text-gray-600 dark:text-gray-400">Processing...</span>
380
+ <span id="progress-text" class="font-medium">0%</span>
381
+ </div>
382
+ <div class="h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
383
+ <div id="progress-bar" class="h-full bg-gradient-to-r from-blue-500 to-purple-600 transition-all duration-300" style="width: 0%"></div>
384
+ </div>
385
+ </div>
386
+
387
+ <!-- Download Section -->
388
+ <div id="download-section" class="hidden mt-6 p-6 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-xl">
389
+ <div class="flex items-center justify-between">
390
+ <div class="flex items-center space-x-3">
391
+ <div class="w-12 h-12 rounded-full bg-green-100 dark:bg-green-800 flex items-center justify-center">
392
+ <i data-lucide="check" class="w-6 h-6 text-green-600 dark:text-green-400"></i>
393
+ </div>
394
+ <div>
395
+ <h4 class="font-semibold text-green-900 dark:text-green-100">Ready!</h4>
396
+ <p class="text-sm text-green-700 dark:text-green-300">Your file has been processed successfully</p>
397
+ </div>
398
+ </div>
399
+ <button onclick="downloadProcessedFile()" class="px-6 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg font-medium transition-colors flex items-center space-x-2">
400
+ <i data-lucide="download" class="w-4 h-4"></i>
401
+ <span>Download</span>
402
+ </button>
403
+ </div>
404
+ </div>
405
+ </div>
406
+
407
+ </div>
408
+ </section>
409
+
410
+ <!-- Security Specifications -->
411
+ <section id="security" class="py-20 bg-white dark:bg-gray-800 border-y border-gray-200 dark:border-gray-700">
412
+ <div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
413
+ <div class="text-center mb-12">
414
+ <h2 class="text-3xl font-bold mb-4">Security Specifications</h2>
415
+ <p class="text-gray-600 dark:text-gray-400">Enterprise-grade encryption standards</p>
416
+ </div>
417
+
418
+ <div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
419
+ <!-- Spec Cards -->
420
+ <div class="p-6 rounded-2xl bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 hover:shadow-lg transition-shadow">
421
+ <div class="w-12 h-12 rounded-xl bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center mb-4">
422
+ <i data-lucide="cpu" class="w-6 h-6 text-blue-600"></i>
423
+ </div>
424
+ <h3 class="font-semibold mb-2">Algorithm</h3>
425
+ <p class="text-2xl font-bold text-blue-600">AES-256-GCM</p>
426
+ <p class="text-sm text-gray-500 mt-1">Galois/Counter Mode</p>
427
+ </div>
428
+
429
+ <div class="p-6 rounded-2xl bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 hover:shadow-lg transition-shadow">
430
+ <div class="w-12 h-12 rounded-xl bg-purple-100 dark:bg-purple-900/30 flex items-center justify-center mb-4">
431
+ <i data-lucide="key" class="w-6 h-6 text-purple-600"></i>
432
+ </div>
433
+ <h3 class="font-semibold mb-2">Key Derivation</h3>
434
+ <p class="text-2xl font-bold text-purple-600">PBKDF2</p>
435
+ <p class="text-sm text-gray-500 mt-1">HMAC-SHA256</p>
436
+ </div>
437
+
438
+ <div class="p-6 rounded-2xl bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 hover:shadow-lg transition-shadow">
439
+ <div class="w-12 h-12 rounded-xl bg-green-100 dark:bg-green-900/30 flex items-center justify-center mb-4">
440
+ <i data-lucide="repeat" class="w-6 h-6 text-green-600"></i>
441
+ </div>
442
+ <h3 class="font-semibold mb-2">Iterations</h3>
443
+ <p class="text-2xl font-bold text-green-600">600,000</p>
444
+ <p class="text-sm text-gray-500 mt-1">Brute-force resistant</p>
445
+ </div>
446
+
447
+ <div class="p-6 rounded-2xl bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 hover:shadow-lg transition-shadow">
448
+ <div class="w-12 h-12 rounded-xl bg-orange-100 dark:bg-orange-900/30 flex items-center justify-center mb-4">
449
+ <i data-lucide="fingerprint" class="w-6 h-6 text-orange-600"></i>
450
+ </div>
451
+ <h3 class="font-semibold mb-2">Salt Length</h3>
452
+ <p class="text-2xl font-bold text-orange-600">16 bytes</p>
453
+ <p class="text-sm text-gray-500 mt-1">128-bit random</p>
454
+ </div>
455
+
456
+ <div class="p-6 rounded-2xl bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 hover:shadow-lg transition-shadow">
457
+ <div class="w-12 h-12 rounded-xl bg-red-100 dark:bg-red-900/30 flex items-center justify-center mb-4">
458
+ <i data-lucide="shuffle" class="w-6 h-6 text-red-600"></i>
459
+ </div>
460
+ <h3 class="font-semibold mb-2">IV Length</h3>
461
+ <p class="text-2xl font-bold text-red-600">12 bytes</p>
462
+ <p class="text-sm text-gray-500 mt-1">96-bit nonce</p>
463
+ </div>
464
+
465
+ <div class="p-6 rounded-2xl bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 hover:shadow-lg transition-shadow">
466
+ <div class="w-12 h-12 rounded-xl bg-indigo-100 dark:bg-indigo-900/30 flex items-center justify-center mb-4">
467
+ <i data-lucide="badge-check" class="w-6 h-6 text-indigo-600"></i>
468
+ </div>
469
+ <h3 class="font-semibold mb-2">Auth Tag</h3>
470
+ <p class="text-2xl font-bold text-indigo-600">128-bit</p>
471
+ <p class="text-sm text-gray-500 mt-1">GCM Authentication</p>
472
+ </div>
473
+ </div>
474
+
475
+ <!-- Data Format -->
476
+ <div class="mt-12 p-6 rounded-2xl bg-gray-900 text-gray-100 font-mono text-sm overflow-x-auto">
477
+ <div class="flex items-center justify-between mb-4">
478
+ <span class="text-gray-400">Data Container Format</span>
479
+ <span class="text-xs bg-gray-800 px-2 py-1 rounded">ENCv1</span>
480
+ </div>
481
+ <code class="block text-green-400">
482
+ ENCv1:{Base64(JSON header + newline + ciphertext)}
483
+ </code>
484
+ <div class="mt-4 text-gray-400 text-xs">
485
+ { "v": 1, "alg": "AES-GCM", "kdf": {"name": "PBKDF2", "hash": "SHA-256", "iters": 600000, "salt_b64": "β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’"}, "iv_b64": "β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’", "keyType": "passphrase", "created": "2025-01-15T12:00:00Z", "type": "text", "orig": null }
486
+ </div>
487
+ </div>
488
+ </div>
489
+ </section>
490
+
491
+ <!-- Features Grid -->
492
+ <section class="py-20 px-4 sm:px-6 lg:px-8">
493
+ <div class="max-w-6xl mx-auto">
494
+ <div class="grid md:grid-cols-3 gap-8">
495
+ <div class="text-center p-6">
496
+ <div class="w-16 h-16 mx-auto mb-4 rounded-2xl bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center shadow-lg">
497
+ <i data-lucide="server-off" class="w-8 h-8 text-white"></i>
498
+ </div>
499
+ <h3 class="text-xl font-bold mb-2">Zero Server Storage</h3>
500
+ <p class="text-gray-600 dark:text-gray-400">All encryption happens locally in your browser. No data is ever transmitted to any server.</p>
501
+ </div>
502
+
503
+ <div class="text-center p-6">
504
+ <div class="w-16 h-16 mx-auto mb-4 rounded-2xl bg-gradient-to-br from-purple-500 to-purple-600 flex items-center justify-center shadow-lg">
505
+ <i data-lucide="code" class="w-8 h-8 text-white"></i>
506
+ </div>
507
+ <h3 class="text-xl font-bold mb-2">Open Source</h3>
508
+ <p class="text-gray-600 dark:text-gray-400">Fully auditable code. Verify the encryption implementation yourself. No backdoors possible.</p>
509
+ </div>
510
+
511
+ <div class="text-center p-6">
512
+ <div class="w-16 h-16 mx-auto mb-4 rounded-2xl bg-gradient-to-br from-green-500 to-green-600 flex items-center justify-center shadow-lg">
513
+ <i data-lucide="zap" class="w-8 h-8 text-white"></i>
514
+ </div>
515
+ <h3 class="text-xl font-bold mb-2">Fast & Efficient</h3>
516
+ <p class="text-gray-600 dark:text-gray-400">Optimized WebCrypto API implementation. Handle files up to 10MB with ease.</p>
517
+ </div>
518
+ </div>
519
+ </div>
520
+ </section>
521
+
522
+ <!-- Footer -->
523
+ <footer class="bg-gray-900 text-gray-400 py-12 border-t border-gray-800">
524
+ <div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
525
+ <div class="flex flex-col md:flex-row justify-between items-center">
526
+ <div class="flex items-center space-x-3 mb-4 md:mb-0">
527
+ <div class="w-8 h-8 bg-gradient-to-br from-blue-500 to-purple-600 rounded-lg flex items-center justify-center">
528
+ <i data-lucide="shield-check" class="w-5 h-5 text-white"></i>
529
+ </div>
530
+ <span class="text-lg font-bold text-white">SecureCrypt</span>
531
+ </div>
532
+
533
+ <div class="text-sm">
534
+ <p>Client-side encryption tool. No data leaves your device.</p>
535
+ </div>
536
+ </div>
537
+
538
+ <div class="mt-8 pt-8 border-t border-gray-800 text-xs text-center">
539
+ <p class="mb-2"><strong>Security Notice:</strong> All operations occur locally. No key recovery possible. Protects at-rest data only.</p>
540
+ <p>&copy; 2025 SecureCrypt. Open source encryption utility.</p>
541
+ </div>
542
+ </div>
543
+ </footer>
544
+
545
+ <!-- Toast Container -->
546
+ <div id="toast-container" class="fixed bottom-4 right-4 z-50 flex flex-col space-y-2"></div>
547
+
548
+ <script>
549
+ // Initialize Lucide icons
550
+ lucide.createIcons();
551
+
552
+ // State management
553
+ let currentMode = 'text';
554
+ let currentOperation = 'encrypt';
555
+ let selectedFile = null;
556
+ let processedFileData = null;
557
+
558
+ // Theme toggle
559
+ function toggleTheme() {
560
+ if (document.documentElement.classList.contains('dark')) {
561
+ document.documentElement.classList.remove('dark');
562
+ localStorage.theme = 'light';
563
+ } else {
564
+ document.documentElement.classList.add('dark');
565
+ localStorage.theme = 'dark';
566
+ }
567
+ }
568
+
569
+ // Initialize theme
570
+ if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
571
+ document.documentElement.classList.add('dark');
572
+ }
573
+
574
+ // Mode switching
575
+ function switchMode(mode) {
576
+ currentMode = mode;
577
+
578
+ // Update tabs
579
+ document.getElementById('tab-text').className = mode === 'text'
580
+ ? 'tab-active px-6 py-3 rounded-xl font-medium transition-all duration-200 flex items-center space-x-2'
581
+ : 'px-6 py-3 rounded-xl font-medium transition-all duration-200 flex items-center space-x-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200';
582
+
583
+ document.getElementById('tab-file').className = mode === 'file'
584
+ ? 'tab-active px-6 py-3 rounded-xl font-medium transition-all duration-200 flex items-center space-x-2'
585
+ : 'px-6 py-3 rounded-xl font-medium transition-all duration-200 flex items-center space-x-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200';
586
+
587
+ // Show/hide interfaces
588
+ document.getElementById('interface-text').classList.toggle('hidden', mode !== 'text');
589
+ document.getElementById('interface-file').classList.toggle('hidden', mode !== 'file');
590
+ }
591
+
592
+ // Operation switching
593
+ function setOperation(op) {
594
+ currentOperation = op;
595
+
596
+ const indicator = document.getElementById('operation-indicator');
597
+ const btnEncrypt = document.getElementById('btn-encrypt');
598
+ const btnDecrypt = document.getElementById('btn-decrypt');
599
+ const actionBtn = document.getElementById('action-btn');
600
+ const actionIcon = document.getElementById('action-icon');
601
+ const actionText = document.getElementById('action-text');
602
+ const fileBtn = document.getElementById('file-action-btn');
603
+
604
+ if (op === 'encrypt') {
605
+ indicator.style.left = '4px';
606
+ btnEncrypt.classList.remove('text-gray-600', 'dark:text-gray-400');
607
+ btnDecrypt.classList.add('text-gray-600', 'dark:text-gray-400');
608
+
609
+ actionBtn.classList.remove('from-amber-500', 'to-orange-600');
610
+ actionBtn.classList.add('from-blue-600', 'to-purple-600');
611
+ actionIcon.setAttribute('data-lucide', 'lock');
612
+ actionText.textContent = 'Encrypt';
613
+
614
+ if (fileBtn) {
615
+ fileBtn.innerHTML = '<i data-lucide="lock" class="w-5 h-5"></i><span>Encrypt File</span>';
616
+ fileBtn.classList.remove('from-amber-500', 'to-orange-600');
617
+ fileBtn.classList.add('from-blue-600', 'to-purple-600');
618
+ }
619
+ } else {
620
+ indicator.style.left = 'calc(50% + 4px)';
621
+ btnDecrypt.classList.remove('text-gray-600', 'dark:text-gray-400');
622
+ btnEncrypt.classList.add('text-gray-600', 'dark:text-gray-400');
623
+
624
+ actionBtn.classList.remove('from-blue-600', 'to-purple-600');
625
+ actionBtn.classList.add('from-amber-500', 'to-orange-600');
626
+ actionIcon.setAttribute('data-lucide', 'unlock');
627
+ actionText.textContent = 'Decrypt';
628
+
629
+ if (fileBtn) {
630
+ fileBtn.innerHTML = '<i data-lucide="unlock" class="w-5 h-5"></i><span>Decrypt File</span>';
631
+ fileBtn.classList.remove('from-blue-600', 'to-purple-600');
632
+ fileBtn.classList.add('from-amber-500', 'to-orange-600');
633
+ }
634
+ }
635
+
636
+ lucide.createIcons();
637
+ }
638
+
639
+ // Password strength checker
640
+ function checkPasswordStrength() {
641
+ const password = document.getElementById('password-input').value;
642
+ const bar = document.getElementById('strength-bar');
643
+ const text = document.getElementById('strength-text');
644
+
645
+ let strength = 0;
646
+ if (password.length > 8) strength++;
647
+ if (password.length > 12) strength++;
648
+ if (/[A-Z]/.test(password)) strength++;
649
+ if (/[0-9]/.test(password)) strength++;
650
+ if (/[^A-Za-z0-9]/.test(password)) strength++;
651
+
652
+ bar.className = 'h-full transition-all duration-300 ';
653
+
654
+ if (password.length === 0) {
655
+ bar.style.width = '0%';
656
+ text.textContent = 'Empty';
657
+ text.className = 'text-xs font-medium text-gray-500';
658
+ } else if (strength < 2) {
659
+ bar.style.width = '25%';
660
+ bar.classList.add('strength-weak');
661
+ text.textContent = 'Weak';
662
+ text.className = 'text-xs font-medium text-red-500';
663
+ } else if (strength < 4) {
664
+ bar.style.width = '50%';
665
+ bar.classList.add('strength-fair');
666
+ text.textContent = 'Fair';
667
+ text.className = 'text-xs font-medium text-amber-500';
668
+ } else if (strength < 5) {
669
+ bar.style.width = '75%';
670
+ bar.classList.add('strength-good');
671
+ text.textContent = 'Good';
672
+ text.className = 'text-xs font-medium text-blue-500';
673
+ } else {
674
+ bar.style.width = '100%';
675
+ bar.classList.add('strength-strong');
676
+ text.textContent = 'Strong';
677
+ text.className = 'text-xs font-medium text-green-500';
678
+ }
679
+ }
680
+
681
+ // Generate secure password
682
+ function generatePassword() {
683
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+~`|}{[]:;?><,./-=';
684
+ let password = '';
685
+ const length = 24;
686
+
687
+ const array = new Uint32Array(length);
688
+ crypto.getRandomValues(array);
689
+
690
+ for (let i = 0; i < length; i++) {
691
+ password += chars[array[i] % chars.length];
692
+ }
693
+
694
+ document.getElementById('password-input').value = password;
695
+ checkPasswordStrength();
696
+ showToast('Password generated!', 'success');
697
+ }
698
+
699
+ function generateFilePassword() {
700
+ generatePassword();
701
+ document.getElementById('file-password').value = document.getElementById('password-input').value;
702
+ }
703
+
704
+ // Toggle password visibility
705
+ function togglePasswordVisibility() {
706
+ const input = document.getElementById('password-input');
707
+ const icon = document.getElementById('eye-icon');
708
+
709
+ if (input.type === 'password') {
710
+ input.type = 'text';
711
+ icon.setAttribute('data-lucide', 'eye-off');
712
+ } else {
713
+ input.type = 'password';
714
+ icon.setAttribute('data-lucide', 'eye');
715
+ }
716
+ lucide.createIcons();
717
+ }
718
+
719
+ // Character count
720
+ document.getElementById('text-input').addEventListener('input', function() {
721
+ document.getElementById('char-count').textContent = this.value.length + ' chars';
722
+ });
723
+
724
+ // Clear functions
725
+ function clearText() {
726
+ document.getElementById('text-input').value = '';
727
+ document.getElementById('text-output').value = '';
728
+ document.getElementById('char-count').textContent = '0 chars';
729
+ }
730
+
731
+ // Crypto functions
732
+ async function deriveKey(password, salt) {
733
+ const encoder = new TextEncoder();
734
+ const keyMaterial = await crypto.subtle.importKey(
735
+ 'raw',
736
+ encoder.encode(password),
737
+ { name: 'PBKDF2' },
738
+ false,
739
+ ['deriveKey']
740
+ );
741
+
742
+ return crypto.subtle.deriveKey(
743
+ {
744
+ name: 'PBKDF2',
745
+ salt: salt,
746
+ iterations: 600000,
747
+ hash: 'SHA-256'
748
+ },
749
+ keyMaterial,
750
+ { name: 'AES-GCM', length: 256 },
751
+ false,
752
+ ['encrypt', 'decrypt']
753
+ );
754
+ }
755
+
756
+ async function encryptText(text, password) {
757
+ const encoder = new TextEncoder();
758
+ const salt = crypto.getRandomValues(new Uint8Array(16));
759
+ const iv = crypto.getRandomValues(new Uint8Array(12));
760
+
761
+ const key = await deriveKey(password, salt);
762
+ const encrypted = await crypto.subtle.encrypt(
763
+ { name: 'AES-GCM', iv: iv },
764
+ key,
765
+ encoder.encode(text)
766
+ );
767
+
768
+ const header = {
769
+ v: 1,
770
+ alg: 'AES-GCM',
771
+ kdf: {
772
+ name: 'PBKDF2',
773
+ hash: 'SHA-256',
774
+ iters: 600000,
775
+ salt_b64: btoa(String.fromCharCode(...salt))
776
+ },
777
+ iv_b64: btoa(String.fromCharCode(...iv)),
778
+ keyType: 'passphrase',
779
+ created: new Date().toISOString(),
780
+ type: 'text',
781
+ orig: null
782
+ };
783
+
784
+ const ciphertext = btoa(String.fromCharCode(...new Uint8Array(encrypted)));
785
+ return 'ENCv1:' + btoa(JSON.stringify(header) + '\n' + ciphertext);
786
+ }
787
+
788
+ async function decryptText(encryptedData, password) {
789
+ if (!encryptedData.startsWith('ENCv1:')) {
790
+ throw new Error('Invalid format');
791
+ }
792
+
793
+ const payload = atob(encryptedData.slice(6));
794
+ const newlineIndex = payload.indexOf('\n');
795
+ const header = JSON.parse(payload.slice(0, newlineIndex));
796
+ const ciphertext = payload.slice(newlineIndex + 1);
797
+
798
+ const salt = Uint8Array.from(atob(header.kdf.salt_b64), c => c.charCodeAt(0));
799
+ const iv = Uint8Array.from(atob(header.iv_b64), c => c.charCodeAt(0));
800
+
801
+ const key = await deriveKey(password, salt);
802
+ const decrypted = await crypto.subtle.decrypt(
803
+ { name: 'AES-GCM', iv: iv },
804
+ key,
805
+ Uint8Array.from(atob(ciphertext), c => c.charCodeAt(0))
806
+ );
807
+
808
+ return new TextDecoder().decode(decrypted);
809
+ }
810
+
811
+ // Process text
812
+ async function processText() {
813
+ const input = document.getElementById('text-input').value;
814
+ const password = document.getElementById('password-input').value;
815
+ const output = document.getElementById('text-output');
816
+ const overlay = document.getElementById('output-overlay');
817
+
818
+ if (!input || !password) {
819
+ showToast('Please enter both text and password', 'error');
820
+ return;
821
+ }
822
+
823
+ overlay.classList.remove('hidden');
824
+
825
+ try {
826
+ if (currentOperation === 'encrypt') {
827
+ const result = await encryptText(input, password);
828
+ output.value = result;
829
+ showToast('Text encrypted successfully!', 'success');
830
+ } else {
831
+ const result = await decryptText(input, password);
832
+ output.value = result;
833
+ showToast('Text decrypted successfully!', 'success');
834
+ }
835
+ } catch (error) {
836
+ showToast('Error: ' + (currentOperation === 'decrypt' ? 'Invalid password or corrupted data' : error.message), 'error');
837
+ } finally {
838
+ overlay.classList.add('hidden');
839
+ }
840
+ }
841
+
842
+ // Copy output
843
+ function copyOutput() {
844
+ const output = document.getElementById('text-output');
845
+ if (!output.value) return;
846
+
847
+ output.select();
848
+ document.execCommand('copy');
849
+ showToast('Copied to clipboard!', 'success');
850
+ }
851
+
852
+ // Download output
853
+ function downloadOutput() {
854
+ const output = document.getElementById('text-output').value;
855
+ if (!output) return;
856
+
857
+ const blob = new Blob([output], { type: 'text/plain' });
858
+ const url = URL.createObjectURL(blob);
859
+ const a = document.createElement('a');
860
+ a.href = url;
861
+ a.download = currentOperation === 'encrypt' ? 'encrypted.txt' : 'decrypted.txt';
862
+ a.click();
863
+ URL.revokeObjectURL(url);
864
+ showToast('File downloaded!', 'success');
865
+ }
866
+
867
+ // File handling
868
+ function handleDragOver(e) {
869
+ e.preventDefault();
870
+ e.currentTarget.classList.add('drag-over');
871
+ }
872
+
873
+ function handleDragLeave(e) {
874
+ e.currentTarget.classList.remove('drag-over');
875
+ }
876
+
877
+ function handleDrop(e) {
878
+ e.preventDefault();
879
+ e.currentTarget.classList.remove('drag-over');
880
+
881
+ const files = e.dataTransfer.files;
882
+ if (files.length > 0) {
883
+ processSelectedFile(files[0]);
884
+ }
885
+ }
886
+
887
+ function handleFileSelect(e) {
888
+ if (e.target.files.length > 0) {
889
+ processSelectedFile(e.target.files[0]);
890
+ }
891
+ }
892
+
893
+ function processSelectedFile(file) {
894
+ if (file.size > 10 * 1024 * 1024) {
895
+ showToast('File too large. Max 10MB allowed.', 'error');
896
+ return;
897
+ }
898
+
899
+ selectedFile = file;
900
+ document.getElementById('file-info').classList.remove('hidden');
901
+ document.getElementById('file-name').textContent = file.name;
902
+ document.getElementById('file-size').textContent = (file.size / 1024).toFixed(1) + ' KB';
903
+ document.getElementById('file-action-btn').disabled = false;
904
+ }
905
+
906
+ function clearFile(e) {
907
+ e.stopPropagation();
908
+ selectedFile = null;
909
+ document.getElementById('file-info').classList.add('hidden');
910
+ document.getElementById('file-input').value = '';
911
+ document.getElementById('file-action-btn').disabled = true;
912
+ document.getElementById('download-section').classList.add('hidden');
913
+ }
914
+
915
+ async function processFile() {
916
+ if (!selectedFile) return;
917
+
918
+ const password = document.getElementById('file-password').value;
919
+ if (!password) {
920
+ showToast('Please enter a password', 'error');
921
+ return;
922
+ }
923
+
924
+ const progressContainer = document.getElementById('progress-container');
925
+ const progressBar = document.getElementById('progress-bar');
926
+ const progressText = document.getElementById('progress-text');
927
+ const btn = document.getElementById('file-action-btn');
928
+
929
+ progressContainer.classList.remove('hidden');
930
+ btn.disabled = true;
931
+
932
+ try {
933
+ const reader = new FileReader();
934
+
935
+ reader.onprogress = (e) => {
936
+ if (e.lengthComputable) {
937
+ const percent = (e.loaded / e.total) * 50;
938
+ progressBar.style.width = percent + '%';
939
+ progressText.textContent = Math.round(percent) + '%';
940
+ }
941
+ };
942
+
943
+ reader.onload = async (e) => {
944
+ const content = e.target.result;
945
+
946
+ try {
947
+ let result;
948
+ if (currentOperation === 'encrypt') {
949
+ const bytes = new Uint8Array(content);
950
+ const base64 = btoa(String.fromCharCode(...bytes));
951
+ result = await encryptText(base64, password);
952
+ } else {
953
+ const decrypted = await decryptText(content, password);
954
+ result = Uint8Array.from(atob(decrypted), c => c.charCodeAt(0));
955
+ }
956
+
957
+ progressBar.style.width = '100%';
958
+ progressText.textContent = '100%';
959
+
960
+ processedFileData = result;
961
+ document.getElementById('download-section').classList.remove('hidden');
962
+ showToast('File processed successfully!', 'success');
963
+
964
+ } catch (error) {
965
+ showToast('Error processing file: ' + error.message, 'error');
966
+ }
967
+ };
968
+
969
+ if (currentOperation === 'encrypt') {
970
+ reader.readAsArrayBuffer(selectedFile);
971
+ } else {
972
+ reader.readAsText(selectedFile);
973
+ }
974
+
975
+ } catch (error) {
976
+ showToast('Error: ' + error.message, 'error');
977
+ btn.disabled = false;
978
+ }
979
+ }
980
+
981
+ function downloadProcessedFile() {
982
+ if (!processedFileData) return;
983
+
984
+ let blob, filename;
985
+
986
+ if (currentOperation === 'encrypt') {
987
+ blob = new Blob([processedFileData], { type: 'text/plain' });
988
+ filename = selectedFile.name + '.encrypted';
989
+ } else {
990
+ blob = new Blob([processedFileData], { type: 'application/octet-stream' });
991
+ filename = selectedFile.name.replace('.encrypted', '') + '.decrypted';
992
+ }
993
+
994
+ const url = URL.createObjectURL(blob);
995
+ const a = document.createElement('a');
996
+ a.href = url;
997
+ a.download = filename;
998
+ a.click();
999
+ URL.revokeObjectURL(url);
1000
+
1001
+ showToast('Download started!', 'success');
1002
+ }
1003
+
1004
+ // Toast notifications
1005
+ function showToast(message, type = 'info') {
1006
+ const container = document.getElementById('toast-container');
1007
+ const toast = document.createElement('div');
1008
+
1009
+ const colors = {
1010
+ success: 'bg-green-500',
1011
+ error: 'bg-red-500',
1012
+ info: 'bg-blue-500'
1013
+ };
1014
+
1015
+ const icons = {
1016
+ success: 'check-circle',
1017
+ error: 'x-circle',
1018
+ info: 'info'
1019
+ };
1020
+
1021
+ toast.className = `toast ${colors[type]} text-white px-6 py-3 rounded-xl shadow-lg flex items-center space-x-2 min-w-[300px]`;
1022
+ toast.innerHTML = `
1023
+ <i data-lucide="${icons[type]}" class="w-5 h-5"></i>
1024
+ <span class="font-medium">${message}</span>
1025
+ `;
1026
+
1027
+ container.appendChild(toast);
1028
+ lucide.createIcons();
1029
+
1030
+ setTimeout(() => {
1031
+ toast.style.opacity = '0';
1032
+ toast.style.transform = 'translateX(100%)';
1033
+ setTimeout(() => toast.remove(), 300);
1034
+ }, 3000);
1035
+ }
1036
+
1037
+ // Keyboard shortcuts
1038
+ document.addEventListener('keydown', (e) => {
1039
+ if (e.ctrlKey || e.metaKey) {
1040
+ if (e.key === 'Enter') {
1041
+ if (currentMode === 'text') {
1042
+ processText();
1043
+ } else {
1044
+ processFile();
1045
+ }
1046
+ }
1047
+ }
1048
+ });
1049
+ </script>
1050
+ <script src="https://deepsite.hf.co/deepsite-badge.js"></script>
1051
+ </body>
1052
+ </html>