app.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import os
  2. import argparse
  3. import uuid
  4. import shutil
  5. from datetime import datetime, timedelta
  6. from flask import Flask, render_template, request, jsonify, send_file, redirect, url_for
  7. from werkzeug.utils import secure_filename
  8. from dotenv import load_dotenv
  9. import json
  10. # Cargar variables de entorno desde .env
  11. load_dotenv()
  12. app = Flask(__name__)
  13. app.config['MAX_CONTENT_LENGTH'] = int(os.getenv('MAX_FILE_SIZE', 16 * 1024 * 1024)) # 16MB max file size
  14. app.config['UPLOAD_FOLDER'] = os.getenv('UPLOAD_FOLDER', 'uploads')
  15. app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'tu_clave_secreta_aqui')
  16. # Manejador de errores para archivos demasiado grandes
  17. @app.errorhandler(413)
  18. def too_large(e):
  19. return jsonify({
  20. 'error': f'El archivo es demasiado grande. Tamaño máximo: {app.config["MAX_CONTENT_LENGTH"] // (1024*1024)}MB'
  21. }), 413
  22. # Manejador de errores general
  23. @app.errorhandler(500)
  24. def internal_error(e):
  25. return jsonify({'error': 'Error interno del servidor'}), 500
  26. @app.errorhandler(404)
  27. def not_found(e):
  28. return jsonify({'error': 'Página no encontrada'}), 404
  29. # Verificar y crear carpeta de uploads si no existe
  30. def ensure_upload_folder():
  31. if not os.path.exists(app.config['UPLOAD_FOLDER']):
  32. os.makedirs(app.config['UPLOAD_FOLDER'])
  33. print(f"Carpeta '{app.config['UPLOAD_FOLDER']}' creada automáticamente.")
  34. # Configurar argumentos de línea de comandos
  35. def parse_arguments():
  36. parser = argparse.ArgumentParser(description='Servidor de archivos temporales')
  37. parser.add_argument('--host', default=os.getenv('HOST', '127.0.0.1'), help='Host del servidor (default: 127.0.0.1)')
  38. parser.add_argument('--port', type=int, default=int(os.getenv('PORT', 5000)), help='Puerto del servidor (default: 5000)')
  39. parser.add_argument('--https', action='store_true', help='Usar HTTPS')
  40. parser.add_argument('--debug', action='store_true', default=os.getenv('DEBUG', 'False').lower() == 'true', help='Modo debug')
  41. return parser.parse_args()
  42. @app.route('/')
  43. def index():
  44. """Página principal para subir archivos"""
  45. # Pasar configuración al template
  46. max_file_size = app.config['MAX_CONTENT_LENGTH']
  47. max_file_size_mb = max_file_size // (1024 * 1024)
  48. return render_template('index.html',
  49. max_file_size=max_file_size,
  50. max_file_size_mb=max_file_size_mb)
  51. @app.route('/view')
  52. def view():
  53. """Página para ver enlaces guardados en localStorage"""
  54. return render_template('view.html')
  55. @app.route('/upload', methods=['POST'])
  56. def upload_file():
  57. """Manejar la subida de archivos"""
  58. try:
  59. # Verificar si hay archivo en la request
  60. if 'file' not in request.files:
  61. return jsonify({'error': 'No se seleccionó ningún archivo'}), 400
  62. file = request.files['file']
  63. if file.filename == '':
  64. return jsonify({'error': 'No se seleccionó ningún archivo'}), 400
  65. # Validar tamaño del archivo antes de procesar
  66. max_size = app.config['MAX_CONTENT_LENGTH']
  67. max_size_mb = max_size // (1024 * 1024)
  68. # Verificar content_length si está disponible
  69. if request.content_length and request.content_length > max_size:
  70. return jsonify({
  71. 'error': f'El archivo es demasiado grande. Tamaño máximo: {max_size_mb}MB'
  72. }), 413
  73. # Verificar el tamaño del archivo después de recibirlo
  74. if file:
  75. # Leer el archivo en chunks para verificar el tamaño
  76. file.seek(0, 2) # Ir al final del archivo
  77. file_size = file.tell()
  78. file.seek(0) # Volver al inicio
  79. if file_size > max_size:
  80. return jsonify({
  81. 'error': f'El archivo es demasiado grande. Tamaño máximo: {max_size_mb}MB'
  82. }), 413
  83. # Generar nombre único para el archivo
  84. filename = secure_filename(file.filename)
  85. if not filename:
  86. return jsonify({'error': 'Nombre de archivo no válido'}), 400
  87. file_id = str(uuid.uuid4())
  88. file_extension = os.path.splitext(filename)[1]
  89. unique_filename = f"{file_id}{file_extension}"
  90. # Guardar archivo
  91. file_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename)
  92. file.save(file_path)
  93. # Crear enlace temporal (expira en 24 horas)
  94. # Usar el dominio configurado o el host actual
  95. domain = os.getenv('DOMAIN', request.host)
  96. protocol = 'https' if args.https else 'http'
  97. download_url = f"{protocol}://{domain}/download/{file_id}"
  98. return jsonify({
  99. 'success': True,
  100. 'download_url': download_url,
  101. 'file_id': file_id,
  102. 'original_filename': filename,
  103. 'expires_at': (datetime.now() + timedelta(hours=24)).isoformat()
  104. })
  105. else:
  106. return jsonify({'error': 'No se pudo procesar el archivo'}), 400
  107. except Exception as e:
  108. print(f"Error en upload: {str(e)}")
  109. return jsonify({'error': 'Error interno del servidor'}), 500
  110. @app.route('/download/<file_id>')
  111. def download_file(file_id):
  112. """Descargar archivo por ID"""
  113. # Buscar archivo por ID
  114. for filename in os.listdir(app.config['UPLOAD_FOLDER']):
  115. if filename.startswith(file_id):
  116. file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
  117. return send_file(file_path, as_attachment=True)
  118. return "Archivo no encontrado", 404
  119. @app.route('/api/links')
  120. def get_links():
  121. """API para obtener enlaces guardados (simulado)"""
  122. # En una implementación real, esto vendría de una base de datos
  123. return jsonify([])
  124. if __name__ == '__main__':
  125. args = parse_arguments()
  126. # Asegurar que existe la carpeta de uploads
  127. ensure_upload_folder()
  128. # Configurar protocolo
  129. protocol = 'https' if args.https else 'http'
  130. print(f"Servidor iniciando en {protocol}://{args.host}:{args.port}")
  131. print(f"Modo debug: {'Activado' if args.debug else 'Desactivado'}")
  132. app.run(
  133. host=args.host,
  134. port=args.port,
  135. debug=args.debug
  136. )