mike23415 commited on
Commit
592595c
Β·
verified Β·
1 Parent(s): fab4a8e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -49
app.py CHANGED
@@ -33,7 +33,7 @@ ALLOWED_EXTENSIONS = {
33
  }
34
 
35
  def get_file_type(filename):
36
- """Determine file type based on extension - NO CHANGES NEEDED"""
37
  if not filename:
38
  return 'unknown'
39
 
@@ -163,7 +163,7 @@ def index():
163
 
164
  @app.route("/api/store", methods=["POST"])
165
  def store():
166
- """Store encrypted secret with enhanced encrypted file support"""
167
  try:
168
  form = request.form
169
  data = form.get("data")
@@ -178,23 +178,32 @@ def store():
178
  theme = form.get("theme", "default")
179
  password_hint = form.get("password_hint", "")
180
 
181
- # Handle ENCRYPTED file data from frontend
182
- encrypted_file = form.get("encrypted_file") # NEW: Get encrypted file data
183
- file_name = form.get("file_name") # NEW: Get file name
184
- file_type = form.get("file_type") # NEW: Get file type
185
- file_size = form.get("file_size") # NEW: Get original file size
186
-
187
- # REMOVE the old file handling code that processed raw files
188
- # No need to handle 'file' in request.files anymore since frontend sends encrypted data
189
-
190
- # Validate encrypted file data if present
191
- if encrypted_file:
192
- if not file_name or not file_type:
193
- return jsonify({"error": "File name and type required for encrypted files"}), 400
194
-
195
- # Optional: Validate file size (encrypted data will be larger due to base64 encoding)
196
- if file_size and int(file_size) > MAX_FILE_SIZE:
197
- return jsonify({"error": f"File too large. Max size: {MAX_FILE_SIZE/1024/1024:.1f}MB"}), 400
 
 
 
 
 
 
 
 
 
198
 
199
  # Generate IDs
200
  secret_id = str(uuid.uuid4())
@@ -204,13 +213,12 @@ def store():
204
  while short_id in SHORT_LINKS:
205
  short_id = generate_short_id()
206
 
207
- # Store secret with encrypted file data
208
  SECRETS[secret_id] = {
209
  "data": data,
210
- "encrypted_file": encrypted_file, # NEW: Store encrypted file data
211
- "file_name": file_name, # NEW: Store file name
212
- "file_type": file_type, # NEW: Store file type
213
- "file_size": file_size, # NEW: Store original file size
214
  "expire_at": time.time() + ttl,
215
  "view_once": view_once,
216
  "delay_seconds": delay_seconds,
@@ -235,7 +243,7 @@ def store():
235
  "short_url": f"{base_url}/s/{short_id}",
236
  "qr_code": qr_code,
237
  "expires_at": SECRETS[secret_id]["expire_at"],
238
- "has_file": encrypted_file is not None # MODIFIED: Check encrypted_file instead
239
  })
240
 
241
  except Exception as e:
@@ -243,7 +251,7 @@ def store():
243
 
244
  @app.route("/api/fetch/<secret_id>")
245
  def fetch(secret_id):
246
- """Fetch encrypted secret with encrypted file data"""
247
  try:
248
  # Check if it's a short link
249
  if secret_id in SHORT_LINKS:
@@ -264,7 +272,7 @@ def fetch(secret_id):
264
  del SHORT_LINKS[short_id]
265
  return jsonify({"error": "Secret has expired"}), 410
266
 
267
- # Check for verify_only parameter
268
  verify_only = request.args.get('verify_only', 'false').lower() == 'true'
269
 
270
  # Only record access and increment count if NOT verify_only
@@ -284,12 +292,11 @@ def fetch(secret_id):
284
  "access_count": secret["access_count"]
285
  }
286
 
287
- # Include ENCRYPTED file data if present
288
- if secret.get("encrypted_file"):
289
- response["encrypted_file"] = secret["encrypted_file"] # MODIFIED: Return encrypted file
290
- response["file_name"] = secret.get("file_name", "unknown")
291
  response["file_type"] = secret.get("file_type", "unknown")
292
- response["file_size"] = secret.get("file_size")
293
 
294
  # Handle view-once deletion (only if not verify_only)
295
  if secret["view_once"] and not verify_only:
@@ -348,7 +355,7 @@ def get_analytics(secret_id):
348
 
349
  @app.route("/api/secrets")
350
  def list_secrets():
351
- """List all active secrets with encrypted file info"""
352
  try:
353
  current_time = time.time()
354
  active_secrets = []
@@ -368,10 +375,8 @@ def list_secrets():
368
  "created_at": secret["created_at"],
369
  "expires_at": secret["expire_at"],
370
  "view_once": secret["view_once"],
371
- "has_file": secret.get("encrypted_file") is not None, # MODIFIED: Check encrypted_file
372
- "file_name": secret.get("file_name"), # NEW: Include file name
373
- "file_type": secret.get("file_type"), # MODIFIED: File type from metadata
374
- "file_size": secret.get("file_size"), # NEW: Include file size
375
  "theme": secret.get("theme", "default"),
376
  "access_count": secret.get("access_count", 0),
377
  "preview": secret["data"][:100] + "..." if len(secret["data"]) > 100 else secret["data"]
@@ -454,19 +459,16 @@ def get_qr_code(secret_id):
454
 
455
  @app.route("/api/stats")
456
  def get_stats():
457
- """Get overall statistics with encrypted file info"""
458
  try:
459
  total_secrets = len(SECRETS)
460
  total_accesses = sum(len(analytics) for analytics in ANALYTICS.values())
461
 
462
- # Count by file type (now from metadata, not actual files)
463
  file_types = {}
464
  for secret in SECRETS.values():
465
- if secret.get("encrypted_file"): # MODIFIED: Check for encrypted_file
466
- file_type = secret.get("file_type", "unknown")
467
- file_types[file_type] = file_types.get(file_type, 0) + 1
468
- else:
469
- file_types["text"] = file_types.get("text", 0) + 1
470
 
471
  # Count by theme
472
  themes = {}
@@ -479,8 +481,7 @@ def get_stats():
479
  "total_accesses": total_accesses,
480
  "file_types": file_types,
481
  "themes": themes,
482
- "active_short_links": len(SHORT_LINKS),
483
- "encrypted_files": sum(1 for secret in SECRETS.values() if secret.get("encrypted_file")) # NEW
484
  })
485
 
486
  except Exception as e:
@@ -530,8 +531,8 @@ def internal_error(error):
530
  if __name__ == "__main__":
531
  print("πŸ” Sharelock Backend Starting...")
532
  print("πŸ“Š Features enabled:")
533
- print(" βœ… End-to-end encryption (messages + files)") # MODIFIED
534
- print(" βœ… Client-side file encryption (5MB max)") # MODIFIED
535
  print(" βœ… QR code generation")
536
  print(" βœ… Analytics tracking")
537
  print(" βœ… Short URLs")
@@ -539,7 +540,6 @@ if __name__ == "__main__":
539
  print(" βœ… Multiple themes")
540
  print(" βœ… Password hints")
541
  print(" βœ… verify_only parameter support")
542
- print(" πŸ”’ Files never stored unencrypted on server") # NEW
543
  print("πŸš€ Server running on http://0.0.0.0:7860")
544
 
545
  app.run(host="0.0.0.0", port=7860, debug=True)
 
33
  }
34
 
35
  def get_file_type(filename):
36
+ """Determine file type based on extension"""
37
  if not filename:
38
  return 'unknown'
39
 
 
163
 
164
  @app.route("/api/store", methods=["POST"])
165
  def store():
166
+ """Store encrypted secret with enhanced features"""
167
  try:
168
  form = request.form
169
  data = form.get("data")
 
178
  theme = form.get("theme", "default")
179
  password_hint = form.get("password_hint", "")
180
 
181
+ # Handle file upload
182
+ file_data = None
183
+ file_type = None
184
+ file_name = None
185
+
186
+ if 'file' in request.files:
187
+ file = request.files['file']
188
+ if file and file.filename:
189
+ # Check file size
190
+ file.seek(0, os.SEEK_END)
191
+ file_size = file.tell()
192
+ file.seek(0)
193
+
194
+ if file_size > MAX_FILE_SIZE:
195
+ return jsonify({"error": f"File too large. Max size: {MAX_FILE_SIZE/1024/1024:.1f}MB"}), 400
196
+
197
+ # Process file
198
+ file_name = secure_filename(file.filename)
199
+ file_type = get_file_type(file_name)
200
+
201
+ if file_type == 'unknown':
202
+ return jsonify({"error": "File type not supported"}), 400
203
+
204
+ # Read and encode file
205
+ file_content = file.read()
206
+ file_data = base64.b64encode(file_content).decode('utf-8')
207
 
208
  # Generate IDs
209
  secret_id = str(uuid.uuid4())
 
213
  while short_id in SHORT_LINKS:
214
  short_id = generate_short_id()
215
 
216
+ # Store secret
217
  SECRETS[secret_id] = {
218
  "data": data,
219
+ "file_data": file_data,
220
+ "file_type": file_type,
221
+ "file_name": file_name,
 
222
  "expire_at": time.time() + ttl,
223
  "view_once": view_once,
224
  "delay_seconds": delay_seconds,
 
243
  "short_url": f"{base_url}/s/{short_id}",
244
  "qr_code": qr_code,
245
  "expires_at": SECRETS[secret_id]["expire_at"],
246
+ "has_file": file_data is not None
247
  })
248
 
249
  except Exception as e:
 
251
 
252
  @app.route("/api/fetch/<secret_id>")
253
  def fetch(secret_id):
254
+ """Fetch and decrypt secret with analytics - MODIFIED TO HANDLE verify_only"""
255
  try:
256
  # Check if it's a short link
257
  if secret_id in SHORT_LINKS:
 
272
  del SHORT_LINKS[short_id]
273
  return jsonify({"error": "Secret has expired"}), 410
274
 
275
+ # CHECK FOR verify_only PARAMETER
276
  verify_only = request.args.get('verify_only', 'false').lower() == 'true'
277
 
278
  # Only record access and increment count if NOT verify_only
 
292
  "access_count": secret["access_count"]
293
  }
294
 
295
+ # Include file data if present
296
+ if secret.get("file_data"):
297
+ response["file_data"] = secret["file_data"]
 
298
  response["file_type"] = secret.get("file_type", "unknown")
299
+ response["file_name"] = secret.get("file_name", "unknown")
300
 
301
  # Handle view-once deletion (only if not verify_only)
302
  if secret["view_once"] and not verify_only:
 
355
 
356
  @app.route("/api/secrets")
357
  def list_secrets():
358
+ """List all active secrets (for dashboard)"""
359
  try:
360
  current_time = time.time()
361
  active_secrets = []
 
375
  "created_at": secret["created_at"],
376
  "expires_at": secret["expire_at"],
377
  "view_once": secret["view_once"],
378
+ "has_file": secret.get("file_data") is not None,
379
+ "file_type": secret.get("file_type"),
 
 
380
  "theme": secret.get("theme", "default"),
381
  "access_count": secret.get("access_count", 0),
382
  "preview": secret["data"][:100] + "..." if len(secret["data"]) > 100 else secret["data"]
 
459
 
460
  @app.route("/api/stats")
461
  def get_stats():
462
+ """Get overall statistics"""
463
  try:
464
  total_secrets = len(SECRETS)
465
  total_accesses = sum(len(analytics) for analytics in ANALYTICS.values())
466
 
467
+ # Count by file type
468
  file_types = {}
469
  for secret in SECRETS.values():
470
+ file_type = secret.get("file_type", "text")
471
+ file_types[file_type] = file_types.get(file_type, 0) + 1
 
 
 
472
 
473
  # Count by theme
474
  themes = {}
 
481
  "total_accesses": total_accesses,
482
  "file_types": file_types,
483
  "themes": themes,
484
+ "active_short_links": len(SHORT_LINKS)
 
485
  })
486
 
487
  except Exception as e:
 
531
  if __name__ == "__main__":
532
  print("πŸ” Sharelock Backend Starting...")
533
  print("πŸ“Š Features enabled:")
534
+ print(" βœ… End-to-end encryption")
535
+ print(" βœ… File uploads (5MB max)")
536
  print(" βœ… QR code generation")
537
  print(" βœ… Analytics tracking")
538
  print(" βœ… Short URLs")
 
540
  print(" βœ… Multiple themes")
541
  print(" βœ… Password hints")
542
  print(" βœ… verify_only parameter support")
 
543
  print("πŸš€ Server running on http://0.0.0.0:7860")
544
 
545
  app.run(host="0.0.0.0", port=7860, debug=True)