mike23415 commited on
Commit
731c9bc
Β·
verified Β·
1 Parent(s): 78b921e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -40
app.py CHANGED
@@ -163,33 +163,48 @@ def index():
163
 
164
  @app.route("/api/store", methods=["POST"])
165
  def store():
166
- """Store encrypted secret with enhanced features - FIXED FOR JSON REQUEST"""
167
  try:
168
- # Check if request is JSON or form data
169
- if request.is_json:
170
- # Handle JSON request (from frontend)
171
- json_data = request.get_json()
172
- data = json_data.get("data")
173
- ttl = int(json_data.get("ttl", 300))
174
- view_once = json_data.get("view_once", False)
175
- delay_seconds = int(json_data.get("delay_seconds", 0))
176
- theme = json_data.get("theme", "default")
177
- password_hint = json_data.get("password_hint", "")
178
- has_file = json_data.get("has_file", False)
179
- else:
180
- # Handle form data (backward compatibility)
181
- form = request.form
182
- data = form.get("data")
183
- ttl = int(form.get("ttl", 300))
184
- view_once = form.get("view_once", "false").lower() == "true"
185
- delay_seconds = int(form.get("delay_seconds", 0))
186
- theme = form.get("theme", "default")
187
- password_hint = form.get("password_hint", "")
188
- has_file = form.get("has_file", "false").lower() == "true"
189
 
190
  if not data:
191
  return jsonify({"error": "Data is required"}), 400
192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  # Generate IDs
194
  secret_id = str(uuid.uuid4())
195
  short_id = generate_short_id()
@@ -200,13 +215,15 @@ def store():
200
 
201
  # Store secret
202
  SECRETS[secret_id] = {
203
- "data": data, # Contains encrypted message + file data
 
 
 
204
  "expire_at": time.time() + ttl,
205
  "view_once": view_once,
206
  "delay_seconds": delay_seconds,
207
  "theme": theme,
208
  "password_hint": password_hint,
209
- "has_file": has_file,
210
  "created_at": time.time(),
211
  "creator_ip": get_client_ip(request),
212
  "access_count": 0
@@ -226,16 +243,15 @@ def store():
226
  "short_url": f"{base_url}/s/{short_id}",
227
  "qr_code": qr_code,
228
  "expires_at": SECRETS[secret_id]["expire_at"],
229
- "has_file": has_file
230
  })
231
 
232
  except Exception as e:
233
- print(f"Error in store endpoint: {str(e)}") # Add logging
234
  return jsonify({"error": str(e)}), 500
235
 
236
  @app.route("/api/fetch/<secret_id>")
237
  def fetch(secret_id):
238
- """Fetch and decrypt secret with analytics - SIMPLIFIED FOR FRONTEND DECRYPTION"""
239
  try:
240
  # Check if it's a short link
241
  if secret_id in SHORT_LINKS:
@@ -256,7 +272,7 @@ def fetch(secret_id):
256
  del SHORT_LINKS[short_id]
257
  return jsonify({"error": "Secret has expired"}), 410
258
 
259
- # Check for verify_only parameter
260
  verify_only = request.args.get('verify_only', 'false').lower() == 'true'
261
 
262
  # Only record access and increment count if NOT verify_only
@@ -267,16 +283,21 @@ def fetch(secret_id):
267
  # Increment access count
268
  secret["access_count"] += 1
269
 
270
- # SIMPLIFIED RESPONSE - No separate file handling
271
  response = {
272
- "data": secret["data"], # Encrypted data (contains message + file)
273
  "theme": secret.get("theme", "default"),
274
  "delay_seconds": secret.get("delay_seconds", 0),
275
  "password_hint": secret.get("password_hint", ""),
276
- "has_file": secret.get("has_file", False), # File flag for frontend
277
  "access_count": secret["access_count"]
278
  }
279
 
 
 
 
 
 
 
280
  # Handle view-once deletion (only if not verify_only)
281
  if secret["view_once"] and not verify_only:
282
  # Delete the secret
@@ -334,7 +355,7 @@ def get_analytics(secret_id):
334
 
335
  @app.route("/api/secrets")
336
  def list_secrets():
337
- """List all active secrets (for dashboard) - UPDATED FOR FRONTEND FILE ENCRYPTION"""
338
  try:
339
  current_time = time.time()
340
  active_secrets = []
@@ -354,10 +375,11 @@ def list_secrets():
354
  "created_at": secret["created_at"],
355
  "expires_at": secret["expire_at"],
356
  "view_once": secret["view_once"],
357
- "has_file": secret.get("has_file", False), # UPDATED: Use file flag
 
358
  "theme": secret.get("theme", "default"),
359
  "access_count": secret.get("access_count", 0),
360
- "preview": "Encrypted data" # UPDATED: Can't preview encrypted data
361
  })
362
 
363
  return jsonify({
@@ -435,16 +457,18 @@ def get_qr_code(secret_id):
435
  except Exception as e:
436
  return jsonify({"error": str(e)}), 500
437
 
438
- # 5. UPDATE THE STATS ENDPOINT
439
  @app.route("/api/stats")
440
  def get_stats():
441
- """Get overall statistics - UPDATED FOR FRONTEND FILE ENCRYPTION"""
442
  try:
443
  total_secrets = len(SECRETS)
444
  total_accesses = sum(len(analytics) for analytics in ANALYTICS.values())
445
 
446
- # Count secrets with files
447
- secrets_with_files = sum(1 for secret in SECRETS.values() if secret.get("has_file", False))
 
 
 
448
 
449
  # Count by theme
450
  themes = {}
@@ -455,7 +479,7 @@ def get_stats():
455
  return jsonify({
456
  "total_secrets": total_secrets,
457
  "total_accesses": total_accesses,
458
- "secrets_with_files": secrets_with_files, # UPDATED: File count
459
  "themes": themes,
460
  "active_short_links": len(SHORT_LINKS)
461
  })
@@ -508,7 +532,6 @@ if __name__ == "__main__":
508
  print("πŸ” Sharelock Backend Starting...")
509
  print("πŸ“Š Features enabled:")
510
  print(" βœ… End-to-end encryption")
511
- print(" βœ… Frontend file encryption")
512
  print(" βœ… File uploads (5MB max)")
513
  print(" βœ… QR code generation")
514
  print(" βœ… Analytics tracking")
 
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")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
  if not data:
172
  return jsonify({"error": "Data is required"}), 400
173
 
174
+ # Parse parameters
175
+ ttl = int(form.get("ttl", 300))
176
+ view_once = form.get("view_once", "false").lower() == "true"
177
+ delay_seconds = int(form.get("delay_seconds", 0))
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())
210
  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,
225
  "theme": theme,
226
  "password_hint": password_hint,
 
227
  "created_at": time.time(),
228
  "creator_ip": get_client_ip(request),
229
  "access_count": 0
 
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:
 
250
  return jsonify({"error": str(e)}), 500
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
 
283
  # Increment access count
284
  secret["access_count"] += 1
285
 
286
+ # Prepare response
287
  response = {
288
+ "data": secret["data"],
289
  "theme": secret.get("theme", "default"),
290
  "delay_seconds": secret.get("delay_seconds", 0),
291
  "password_hint": secret.get("password_hint", ""),
 
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:
303
  # Delete the secret
 
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"]
383
  })
384
 
385
  return jsonify({
 
457
  except Exception as e:
458
  return jsonify({"error": str(e)}), 500
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 = {}
 
479
  return jsonify({
480
  "total_secrets": total_secrets,
481
  "total_accesses": total_accesses,
482
+ "file_types": file_types,
483
  "themes": themes,
484
  "active_short_links": len(SHORT_LINKS)
485
  })
 
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")