shukdevdattaEX commited on
Commit
2240bb0
·
verified ·
1 Parent(s): e7e488e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -652
app.py CHANGED
@@ -1,658 +1,42 @@
1
- import gradio as gr
2
- from deepface import DeepFace
3
- import numpy as np
 
 
4
 
5
- def verify_faces(nid_image, webcam_image):
6
- """
7
- Verify if two face images match with detailed step-by-step process visualization
8
-
9
- Args:
10
- nid_image: NID card image (numpy array from Gradio)
11
- webcam_image: Webcam/live image (numpy array from Gradio)
12
-
13
- Returns:
14
- Formatted result string with verification details and process steps
15
- """
16
- model_name = "ArcFace" # Using ArcFace model only
17
- try:
18
- # Check if images are provided
19
- if nid_image is None or webcam_image is None:
20
- return """
21
- <div class='error-container'>
22
- <div class='error-icon'>⚠️</div>
23
- <h3>Missing Images</h3>
24
- <p>Please upload both NID and webcam images to proceed</p>
25
- </div>
26
- """
27
-
28
- # Initialize process status
29
- process_steps = {
30
- "face_detection": "⏳ Detecting faces...",
31
- "face_alignment": "⏳ Waiting...",
32
- "preprocessing": "⏳ Waiting...",
33
- "neural_network": "⏳ Waiting...",
34
- "embedding": "⏳ Waiting...",
35
- "calculate_distance": "⏳ Waiting...",
36
- "threshold_comparison": "⏳ Waiting...",
37
- "final_result": "⏳ Waiting..."
38
- }
39
-
40
- # Step updates
41
- process_steps["face_detection"] = "✅ Faces detected in both images"
42
- process_steps["face_alignment"] = "✅ Faces aligned and normalized"
43
- process_steps["preprocessing"] = "✅ Images preprocessed"
44
- process_steps["neural_network"] = f"✅ Processing through {model_name}"
45
-
46
- # Perform face verification
47
- result = DeepFace.verify(
48
- img1_path=nid_image,
49
- img2_path=webcam_image,
50
- model_name=model_name,
51
- enforce_detection=True
52
- )
53
-
54
- # Extract results
55
- verified = result["verified"]
56
- distance = result["distance"]
57
- threshold = result["threshold"]
58
- model_used = result["model"]
59
- detector = result["detector_backend"]
60
- metric = result["similarity_metric"]
61
-
62
- # Step updates
63
- process_steps["embedding"] = "✅ Face embeddings generated"
64
- process_steps["calculate_distance"] = f"✅ Distance: {distance:.4f}"
65
-
66
- if distance < threshold:
67
- process_steps["threshold_comparison"] = f"✅ {distance:.4f} < {threshold:.4f}"
68
- else:
69
- process_steps["threshold_comparison"] = f"❌ {distance:.4f} ≥ {threshold:.4f}"
70
-
71
- # Calculate confidence
72
- if verified:
73
- confidence = ((threshold - distance) / threshold) * 100
74
- status = "MATCH"
75
- status_class = "match"
76
- process_steps["final_result"] = "✅ FACES MATCH"
77
- else:
78
- confidence = ((distance - threshold) / distance) * 100 if distance > 0 else 0
79
- status = "NO MATCH"
80
- status_class = "no-match"
81
- process_steps["final_result"] = "❌ FACES DO NOT MATCH"
82
-
83
- # Format output with enhanced mobile-responsive design
84
- output = f"""
85
- <style>
86
- .verification-container {{
87
- max-width: 1200px;
88
- margin: 0 auto;
89
- padding: 16px;
90
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
91
- }}
92
-
93
- .status-banner {{
94
- padding: 24px;
95
- border-radius: 16px;
96
- text-align: center;
97
- margin-bottom: 24px;
98
- box-shadow: 0 4px 12px rgba(0,0,0,0.1);
99
- animation: slideDown 0.5s ease;
100
- }}
101
-
102
- .status-banner.match {{
103
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
104
- color: white;
105
- }}
106
-
107
- .status-banner.no-match {{
108
- background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
109
- color: white;
110
- }}
111
-
112
- .status-icon {{
113
- font-size: 48px;
114
- margin-bottom: 12px;
115
- }}
116
-
117
- .status-title {{
118
- font-size: 28px;
119
- font-weight: 700;
120
- margin: 8px 0;
121
- letter-spacing: 1px;
122
- }}
123
-
124
- .confidence-bar {{
125
- width: 100%;
126
- max-width: 300px;
127
- height: 12px;
128
- background: rgba(255,255,255,0.3);
129
- border-radius: 20px;
130
- margin: 16px auto;
131
- overflow: hidden;
132
- }}
133
-
134
- .confidence-fill {{
135
- height: 100%;
136
- background: white;
137
- border-radius: 20px;
138
- transition: width 1s ease;
139
- width: {confidence:.1f}%;
140
- }}
141
-
142
- .confidence-text {{
143
- font-size: 20px;
144
- font-weight: 600;
145
- margin-top: 8px;
146
- }}
147
-
148
- .card {{
149
- background: white;
150
- border-radius: 16px;
151
- padding: 20px;
152
- margin-bottom: 20px;
153
- box-shadow: 0 2px 8px rgba(0,0,0,0.08);
154
- border: 1px solid #e5e7eb;
155
- }}
156
-
157
- .card-header {{
158
- display: flex;
159
- align-items: center;
160
- margin-bottom: 16px;
161
- padding-bottom: 12px;
162
- border-bottom: 2px solid #f3f4f6;
163
- }}
164
-
165
- .card-icon {{
166
- font-size: 24px;
167
- margin-right: 12px;
168
- }}
169
-
170
- .card-title {{
171
- font-size: 20px;
172
- font-weight: 700;
173
- color: #1f2937;
174
- margin: 0;
175
- }}
176
-
177
- .step-item {{
178
- margin: 12px 0;
179
- padding: 16px;
180
- border-radius: 12px;
181
- background: #f9fafb;
182
- border-left: 4px solid #6366f1;
183
- transition: transform 0.2s ease;
184
- }}
185
-
186
- .step-item:hover {{
187
- transform: translateX(4px);
188
- }}
189
-
190
- .step-title {{
191
- font-weight: 600;
192
- font-size: 16px;
193
- color: #374151;
194
- margin-bottom: 6px;
195
- }}
196
-
197
- .step-status {{
198
- font-size: 15px;
199
- margin-bottom: 4px;
200
- }}
201
-
202
- .step-description {{
203
- font-size: 13px;
204
- color: #6b7280;
205
- font-style: italic;
206
- margin: 0;
207
- }}
208
-
209
- .metrics-grid {{
210
- display: grid;
211
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
212
- gap: 16px;
213
- margin-top: 16px;
214
- }}
215
-
216
- .metric-item {{
217
- padding: 16px;
218
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
219
- border-radius: 12px;
220
- color: white;
221
- text-align: center;
222
- }}
223
-
224
- .metric-label {{
225
- font-size: 13px;
226
- opacity: 0.9;
227
- margin-bottom: 6px;
228
- }}
229
-
230
- .metric-value {{
231
- font-size: 22px;
232
- font-weight: 700;
233
- }}
234
-
235
- .info-box {{
236
- background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
237
- padding: 16px;
238
- border-radius: 12px;
239
- margin-top: 20px;
240
- border-left: 4px solid #f59e0b;
241
- }}
242
-
243
- .info-title {{
244
- font-weight: 700;
245
- color: #92400e;
246
- margin-bottom: 8px;
247
- font-size: 16px;
248
- }}
249
-
250
- .info-text {{
251
- font-size: 14px;
252
- color: #78350f;
253
- line-height: 1.6;
254
- margin: 6px 0;
255
- }}
256
-
257
- .error-container {{
258
- background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);
259
- padding: 32px;
260
- border-radius: 16px;
261
- text-align: center;
262
- border: 2px solid #ef4444;
263
- }}
264
-
265
- .error-icon {{
266
- font-size: 48px;
267
- margin-bottom: 16px;
268
- }}
269
-
270
- @keyframes slideDown {{
271
- from {{
272
- opacity: 0;
273
- transform: translateY(-20px);
274
- }}
275
- to {{
276
- opacity: 1;
277
- transform: translateY(0);
278
- }}
279
- }}
280
-
281
- /* Mobile Responsive */
282
- @media (max-width: 768px) {{
283
- .verification-container {{
284
- padding: 12px;
285
- }}
286
-
287
- .status-banner {{
288
- padding: 20px 16px;
289
- }}
290
-
291
- .status-icon {{
292
- font-size: 36px;
293
- }}
294
-
295
- .status-title {{
296
- font-size: 22px;
297
- }}
298
-
299
- .confidence-text {{
300
- font-size: 18px;
301
- }}
302
-
303
- .card {{
304
- padding: 16px;
305
- margin-bottom: 16px;
306
- }}
307
-
308
- .card-title {{
309
- font-size: 18px;
310
- }}
311
-
312
- .step-item {{
313
- padding: 12px;
314
- }}
315
-
316
- .step-title {{
317
- font-size: 15px;
318
- }}
319
-
320
- .metrics-grid {{
321
- grid-template-columns: 1fr;
322
- gap: 12px;
323
- }}
324
-
325
- .metric-value {{
326
- font-size: 20px;
327
- }}
328
- }}
329
-
330
- @media (max-width: 480px) {{
331
- .status-title {{
332
- font-size: 20px;
333
- }}
334
-
335
- .card-icon {{
336
- font-size: 20px;
337
- }}
338
-
339
- .card-title {{
340
- font-size: 16px;
341
- }}
342
- }}
343
- </style>
344
-
345
- <div class='verification-container'>
346
- <div class='status-banner {status_class}'>
347
- <div class='status-icon'>{'✅' if verified else '❌'}</div>
348
- <div class='status-title'>{status}</div>
349
- <div class='confidence-bar'>
350
- <div class='confidence-fill'></div>
351
- </div>
352
- <div class='confidence-text'>{confidence:.1f}% Confidence</div>
353
- </div>
354
-
355
- <div class='card'>
356
- <div class='card-header'>
357
- <div class='card-icon'>🔄</div>
358
- <h3 class='card-title'>Verification Process</h3>
359
- </div>
360
-
361
- <div class='step-item'>
362
- <div class='step-title'>Step 1-2: Face Detection</div>
363
- <div class='step-status'>{process_steps["face_detection"]}</div>
364
- <p class='step-description'>Detector: {detector}</p>
365
- </div>
366
-
367
- <div class='step-item'>
368
- <div class='step-title'>Step 3: Face Alignment</div>
369
- <div class='step-status'>{process_steps["face_alignment"]}</div>
370
- <p class='step-description'>Faces rotated and centered</p>
371
- </div>
372
-
373
- <div class='step-item'>
374
- <div class='step-title'>Step 4: Preprocessing</div>
375
- <div class='step-status'>{process_steps["preprocessing"]}</div>
376
- <p class='step-description'>Images standardized</p>
377
- </div>
378
-
379
- <div class='step-item'>
380
- <div class='step-title'>Step 5: Neural Network</div>
381
- <div class='step-status'>{process_steps["neural_network"]}</div>
382
- <p class='step-description'>Deep learning feature extraction</p>
383
- </div>
384
-
385
- <div class='step-item'>
386
- <div class='step-title'>Step 6: Embedding Generation</div>
387
- <div class='step-status'>{process_steps["embedding"]}</div>
388
- <p class='step-description'>Numerical vector creation</p>
389
- </div>
390
-
391
- <div class='step-item'>
392
- <div class='step-title'>Step 7: Distance Calculation</div>
393
- <div class='step-status'>{process_steps["calculate_distance"]}</div>
394
- <p class='step-description'>Metric: {metric}</p>
395
- </div>
396
-
397
- <div class='step-item'>
398
- <div class='step-title'>Step 8: Threshold Comparison</div>
399
- <div class='step-status'>{process_steps["threshold_comparison"]}</div>
400
- <p class='step-description'>Decision boundary check</p>
401
- </div>
402
-
403
- <div class='step-item' style='border-left-color: {"#10b981" if verified else "#ef4444"}; background: {"#ecfdf5" if verified else "#fee2e2"};'>
404
- <div class='step-title'>Step 9: Final Result</div>
405
- <div class='step-status'><b>{process_steps["final_result"]}</b></div>
406
- </div>
407
- </div>
408
-
409
- <div class='card'>
410
- <div class='card-header'>
411
- <div class='card-icon'>📊</div>
412
- <h3 class='card-title'>Detailed Metrics</h3>
413
- </div>
414
-
415
- <div class='metrics-grid'>
416
- <div class='metric-item'>
417
- <div class='metric-label'>Verified Status</div>
418
- <div class='metric-value'>{'YES' if verified else 'NO'}</div>
419
- </div>
420
- <div class='metric-item'>
421
- <div class='metric-label'>Confidence Score</div>
422
- <div class='metric-value'>{confidence:.1f}%</div>
423
- </div>
424
- <div class='metric-item'>
425
- <div class='metric-label'>Distance Score</div>
426
- <div class='metric-value'>{distance:.4f}</div>
427
- </div>
428
- <div class='metric-item'>
429
- <div class='metric-label'>Threshold Value</div>
430
- <div class='metric-value'>{threshold:.4f}</div>
431
- </div>
432
- <div class='metric-item'>
433
- <div class='metric-label'>Model Used</div>
434
- <div class='metric-value' style='font-size: 18px;'>{model_used}</div>
435
- </div>
436
- <div class='metric-item'>
437
- <div class='metric-label'>Similarity Metric</div>
438
- <div class='metric-value' style='font-size: 18px;'>{metric}</div>
439
- </div>
440
- </div>
441
- </div>
442
-
443
- <div class='info-box'>
444
- <div class='info-title'>📖 Understanding the Results</div>
445
- <p class='info-text'><b>Distance Score:</b> How different the faces are (lower = more similar)</p>
446
- <p class='info-text'><b>Threshold:</b> Cutoff point - below this means match</p>
447
- <p class='info-text'><b>Confidence:</b> How certain the system is about the decision</p>
448
- <p class='info-text'><b>Embeddings:</b> Mathematical face representations in high-dimensional space</p>
449
- </div>
450
- </div>
451
- """
452
-
453
- return output
454
-
455
- except ValueError as e:
456
- if "Face could not be detected" in str(e):
457
- return """
458
- <div class='verification-container'>
459
- <div class='error-container'>
460
- <div class='error-icon'>❌</div>
461
- <h3 style='color: #dc2626; margin: 12px 0;'>Face Detection Failed</h3>
462
- <p style='color: #991b1b; margin: 8px 0;'><b>No face detected in one or both images</b></p>
463
- <div style='text-align: left; display: inline-block; margin-top: 16px;'>
464
- <p style='color: #991b1b; margin: 6px 0;'><b>Suggestions:</b></p>
465
- <ul style='color: #991b1b; text-align: left;'>
466
- <li>Ensure clear, visible faces</li>
467
- <li>Use front-facing photos</li>
468
- <li>Improve lighting conditions</li>
469
- <li>Remove obstructions</li>
470
- </ul>
471
- </div>
472
- </div>
473
- </div>
474
- """
475
- else:
476
- return f"""
477
- <div class='verification-container'>
478
- <div class='error-container'>
479
- <div class='error-icon'>⚠️</div>
480
- <h3 style='color: #dc2626;'>Verification Error</h3>
481
- <p style='color: #991b1b;'>{str(e)}</p>
482
- </div>
483
- </div>
484
- """
485
-
486
- except Exception as e:
487
- return f"""
488
- <div class='verification-container'>
489
- <div class='error-container'>
490
- <div class='error-icon'>❌</div>
491
- <h3 style='color: #dc2626;'>System Error</h3>
492
- <p style='color: #991b1b;'>{str(e)}</p>
493
- <p style='color: #991b1b; font-size: 14px; margin-top: 12px;'>Please try again or contact support</p>
494
- </div>
495
- </div>
496
- """
497
 
 
 
498
 
499
- # Custom CSS for the entire Gradio app
500
- custom_css = """
501
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
502
-
503
- * {
504
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important;
505
- }
506
-
507
- .gradio-container {
508
- max-width: 1400px !important;
509
- margin: auto !important;
510
- }
511
-
512
- .main-header {
513
- text-align: center;
514
- padding: 32px 16px;
515
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
516
- color: white;
517
- border-radius: 20px;
518
- margin-bottom: 32px;
519
- box-shadow: 0 8px 24px rgba(102, 126, 234, 0.3);
520
- }
521
-
522
- .main-header h1 {
523
- font-size: 36px;
524
- font-weight: 700;
525
- margin-bottom: 12px;
526
- letter-spacing: -0.5px;
527
- }
528
-
529
- .main-header p {
530
- font-size: 18px;
531
- opacity: 0.95;
532
- margin: 0;
533
- }
534
-
535
- button {
536
- border-radius: 12px !important;
537
- font-weight: 600 !important;
538
- transition: all 0.3s ease !important;
539
- }
540
-
541
- button:hover {
542
- transform: translateY(-2px);
543
- box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important;
544
- }
545
-
546
- .image-container {
547
- border-radius: 16px;
548
- overflow: hidden;
549
- box-shadow: 0 4px 12px rgba(0,0,0,0.08);
550
- }
551
-
552
- @media (max-width: 768px) {
553
- .main-header h1 {
554
- font-size: 28px;
555
- }
556
-
557
- .main-header p {
558
- font-size: 16px;
559
- }
560
-
561
- .main-header {
562
- padding: 24px 16px;
563
- }
564
- }
565
- """
566
 
567
- # Create Gradio Interface
568
- with gr.Blocks(css=custom_css, title="Face Verification System", theme=gr.themes.Ocean()) as demo:
569
-
570
- gr.HTML("""
571
- <div class='main-header'>
572
- <h1>🔐 Face Verification System</h1>
573
- <p>Advanced Deep Learning Face Matching with Process Visualization</p>
574
- </div>
575
- """)
576
-
577
- with gr.Row():
578
- with gr.Column(scale=1):
579
- nid_input = gr.Image(
580
- label="📇 NID Card Image",
581
- type="numpy",
582
- sources=["upload", "webcam"],
583
- height=300,
584
- container=True
585
- )
586
-
587
- with gr.Column(scale=1):
588
- webcam_input = gr.Image(
589
- label="📷 Webcam/Live Image",
590
- type="numpy",
591
- sources=["upload", "webcam"],
592
- height=300,
593
- container=True
594
- )
595
-
596
- verify_button = gr.Button("🔍 Verify Faces with ArcFace", variant="primary", size="lg")
597
-
598
- output_html = gr.HTML(label="Verification Result")
599
-
600
- # Button click event
601
- verify_button.click(
602
- fn=verify_faces,
603
- inputs=[nid_input, webcam_input],
604
- outputs=output_html
605
- )
606
-
607
- with gr.Accordion("📚 How to Use", open=False):
608
- gr.Markdown("""
609
- ### Step-by-Step Guide:
610
-
611
- 1. **Upload NID Image** - Upload or capture the ID card photo with a clear face
612
- 2. **Upload Live Image** - Upload or capture a webcam photo of the person
613
- 3. **Click Verify** - Start the verification process
614
- 4. **View Results** - See detailed step-by-step process and metrics
615
-
616
- ### ⚠️ Best Practices:
617
-
618
- ✅ Use clear, well-lit photos
619
- ✅ Ensure faces are front-facing
620
- ✅ Keep faces unobstructed
621
- ✅ Use high-resolution images
622
-
623
- ❌ Avoid blurry images
624
- ❌ Avoid extreme angles
625
- ❌ Avoid poor lighting
626
- ❌ Avoid multiple faces
627
- """)
628
-
629
- with gr.Accordion("🔬 The 9-Step Process", open=False):
630
- gr.Markdown("""
631
- | Step | Process | Description |
632
- |------|---------|-------------|
633
- | 1-2 | **Face Detection** | Locates and extracts faces from images |
634
- | 3 | **Face Alignment** | Rotates and centers faces |
635
- | 4 | **Preprocessing** | Resizes and normalizes images |
636
- | 5 | **Neural Network** | Deep learning processing |
637
- | 6 | **Embedding** | Converts to numerical vectors |
638
- | 7 | **Distance Calculation** | Measures similarity |
639
- | 8 | **Threshold Check** | Compares against cutoff |
640
- | 9 | **Final Decision** | Returns MATCH or NO MATCH |
641
- """)
642
-
643
- with gr.Accordion("🎯 Available Models", open=False):
644
- gr.Markdown("""
645
- - **ArcFace** ⭐ - State-of-the-art (~99.4% accuracy)
646
- - New Models (very soon)
647
- """)
648
-
649
- gr.Markdown("""
650
- <div style='text-align: center; padding: 20px; color: #6b7280; font-size: 14px;'>
651
- <p><b>🔒 Privacy Notice:</b> Images are processed locally and not stored permanently</p>
652
- <p><b>⚠️ Disclaimer:</b> For educational and demonstration purposes only</p>
653
- </div>
654
- """)
655
 
656
- # Launch the app
657
  if __name__ == "__main__":
658
- demo.launch(share=True, debug=True)
 
 
 
 
1
+ from Crypto.Cipher import AES
2
+ from Crypto.Protocol.KDF import PBKDF2
3
+ import os
4
+ import tempfile
5
+ from dotenv import load_dotenv
6
 
7
+ load_dotenv() # Load all environment variables
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
+ def unpad(data):
10
+ return data[:-data[-1]]
11
 
12
+ def decrypt_and_run():
13
+ # Get password from Hugging Face Secrets environment variable
14
+ password = os.getenv("PASSWORD")
15
+ if not password:
16
+ raise ValueError("PASSWORD secret not found in environment variables")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
+ password = password.encode()
19
+
20
+ with open("code.enc", "rb") as f:
21
+ encrypted = f.read()
22
+
23
+ salt = encrypted[:16]
24
+ iv = encrypted[16:32]
25
+ ciphertext = encrypted[32:]
26
+
27
+ key = PBKDF2(password, salt, dkLen=32, count=1000000)
28
+ cipher = AES.new(key, AES.MODE_CBC, iv)
29
+
30
+ plaintext = unpad(cipher.decrypt(ciphertext))
31
+
32
+ with tempfile.NamedTemporaryFile(suffix=".py", delete=False, mode='wb') as tmp:
33
+ tmp.write(plaintext)
34
+ tmp.flush()
35
+ print(f"[INFO] Running decrypted code from {tmp.name}")
36
+ os.system(f"python {tmp.name}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
 
38
  if __name__ == "__main__":
39
+ decrypt_and_run()
40
+
41
+ # This script decrypts the encrypted code and runs it.
42
+ # Ensure you have the PASSWORD secret set in your Hugging Face Secrets