| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- import os
- import argparse
- import uuid
- import shutil
- from datetime import datetime, timedelta
- from flask import Flask, render_template, request, jsonify, send_file, redirect, url_for
- from werkzeug.utils import secure_filename
- from dotenv import load_dotenv
- import json
- # Cargar variables de entorno desde .env
- load_dotenv()
- app = Flask(__name__)
- app.config['MAX_CONTENT_LENGTH'] = int(os.getenv('MAX_FILE_SIZE', 16 * 1024 * 1024)) # 16MB max file size
- app.config['UPLOAD_FOLDER'] = os.getenv('UPLOAD_FOLDER', 'uploads')
- app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'tu_clave_secreta_aqui')
- # Manejador de errores para archivos demasiado grandes
- @app.errorhandler(413)
- def too_large(e):
- return jsonify({
- 'error': f'El archivo es demasiado grande. Tamaño máximo: {app.config["MAX_CONTENT_LENGTH"] // (1024*1024)}MB'
- }), 413
- # Manejador de errores general
- @app.errorhandler(500)
- def internal_error(e):
- return jsonify({'error': 'Error interno del servidor'}), 500
- @app.errorhandler(404)
- def not_found(e):
- return jsonify({'error': 'Página no encontrada'}), 404
- # Verificar y crear carpeta de uploads si no existe
- def ensure_upload_folder():
- if not os.path.exists(app.config['UPLOAD_FOLDER']):
- os.makedirs(app.config['UPLOAD_FOLDER'])
- print(f"Carpeta '{app.config['UPLOAD_FOLDER']}' creada automáticamente.")
- # Configurar argumentos de línea de comandos
- def parse_arguments():
- parser = argparse.ArgumentParser(description='Servidor de archivos temporales')
- parser.add_argument('--host', default=os.getenv('HOST', '127.0.0.1'), help='Host del servidor (default: 127.0.0.1)')
- parser.add_argument('--port', type=int, default=int(os.getenv('PORT', 5000)), help='Puerto del servidor (default: 5000)')
- parser.add_argument('--https', action='store_true', help='Usar HTTPS')
- parser.add_argument('--debug', action='store_true', default=os.getenv('DEBUG', 'False').lower() == 'true', help='Modo debug')
- return parser.parse_args()
- @app.route('/')
- def index():
- """Página principal para subir archivos"""
- # Pasar configuración al template
- max_file_size = app.config['MAX_CONTENT_LENGTH']
- max_file_size_mb = max_file_size // (1024 * 1024)
-
- return render_template('index.html',
- max_file_size=max_file_size,
- max_file_size_mb=max_file_size_mb)
- @app.route('/view')
- def view():
- """Página para ver enlaces guardados en localStorage"""
- return render_template('view.html')
- @app.route('/upload', methods=['POST'])
- def upload_file():
- """Manejar la subida de archivos"""
- try:
- # Verificar si hay archivo en la request
- if 'file' not in request.files:
- return jsonify({'error': 'No se seleccionó ningún archivo'}), 400
-
- file = request.files['file']
- if file.filename == '':
- return jsonify({'error': 'No se seleccionó ningún archivo'}), 400
-
- # Validar tamaño del archivo antes de procesar
- max_size = app.config['MAX_CONTENT_LENGTH']
- max_size_mb = max_size // (1024 * 1024)
-
- # Verificar content_length si está disponible
- if request.content_length and request.content_length > max_size:
- return jsonify({
- 'error': f'El archivo es demasiado grande. Tamaño máximo: {max_size_mb}MB'
- }), 413
-
- # Verificar el tamaño del archivo después de recibirlo
- if file:
- # Leer el archivo en chunks para verificar el tamaño
- file.seek(0, 2) # Ir al final del archivo
- file_size = file.tell()
- file.seek(0) # Volver al inicio
-
- if file_size > max_size:
- return jsonify({
- 'error': f'El archivo es demasiado grande. Tamaño máximo: {max_size_mb}MB'
- }), 413
-
- # Generar nombre único para el archivo
- filename = secure_filename(file.filename)
- if not filename:
- return jsonify({'error': 'Nombre de archivo no válido'}), 400
-
- file_id = str(uuid.uuid4())
- file_extension = os.path.splitext(filename)[1]
- unique_filename = f"{file_id}{file_extension}"
-
- # Guardar archivo
- file_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename)
- file.save(file_path)
-
- # Crear enlace temporal (expira en 24 horas)
- # Usar el dominio configurado o el host actual
- domain = os.getenv('DOMAIN', request.host)
- protocol = 'https' if args.https else 'http'
- download_url = f"{protocol}://{domain}/download/{file_id}"
-
- return jsonify({
- 'success': True,
- 'download_url': download_url,
- 'file_id': file_id,
- 'original_filename': filename,
- 'expires_at': (datetime.now() + timedelta(hours=24)).isoformat()
- })
- else:
- return jsonify({'error': 'No se pudo procesar el archivo'}), 400
-
- except Exception as e:
- print(f"Error en upload: {str(e)}")
- return jsonify({'error': 'Error interno del servidor'}), 500
- @app.route('/download/<file_id>')
- def download_file(file_id):
- """Descargar archivo por ID"""
- # Buscar archivo por ID
- for filename in os.listdir(app.config['UPLOAD_FOLDER']):
- if filename.startswith(file_id):
- file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
- return send_file(file_path, as_attachment=True)
-
- return "Archivo no encontrado", 404
- @app.route('/api/links')
- def get_links():
- """API para obtener enlaces guardados (simulado)"""
- # En una implementación real, esto vendría de una base de datos
- return jsonify([])
- if __name__ == '__main__':
- args = parse_arguments()
-
- # Asegurar que existe la carpeta de uploads
- ensure_upload_folder()
-
- # Configurar protocolo
- protocol = 'https' if args.https else 'http'
-
- print(f"Servidor iniciando en {protocol}://{args.host}:{args.port}")
- print(f"Modo debug: {'Activado' if args.debug else 'Desactivado'}")
-
- app.run(
- host=args.host,
- port=args.port,
- debug=args.debug
- )
|