Compare commits

..
12 Commits
Author SHA1 Message Date
pablinux fc416cde99 docs: formalizar y detallar objetivos derivados de ideas (WebRTC P2P, Ads, PIN y Burn-after-reading) 2026-10-27 23:15:58 -05:00
pablinux 32d0190ca8 docs: actualizar estado de sincronizacion de repositorio git remoto en tareas.md 2026-10-23 12:56:17 -05:00
pablinux cfda6921f9 security: blindaje contra ejecucion de scripts RCE, Stored XSS, MIME sniffing, Path Traversal y DoS 2026-10-21 01:40:43 -05:00
pablinux 7b58170540 feat: agregar identidad visual e iconos del proyecto (SVG, ICO, PNG) y desplegar en producción 2026-10-20 11:16:49 -05:00
pablinux 8fedd61318 feat: optimizar deteccion HTTPS y registrar puesta en produccion publica con Apache SSL 2026-10-20 10:49:10 -05:00
pablinux 69a3ee98e6 fix(infra): reasignar puerto a 2008 en CT 132 y MCP para liberar puerto 2006 a audio_control 2026-10-20 00:34:03 -05:00
pablinux 035238c08d feat: completar despliegue en produccion CT 132 con supervision de SIAX Monitor y reinicio atomico 2026-10-19 23:55:21 -05:00
pablinux 55608c1abe docs: confirmar autorizacion de Agente ID 86 en sigma-robot y actualizar docs 2026-10-17 03:50:36 -05:00
pablinux 7d72dcaa84 docs: completar reglas.md, tareas.md, actualizar objetivos y enriquecer README con infraestructura MCP 2026-10-17 03:49:20 -05:00
pablinux b3b8aac200 docs: registrar solicitud en centro de agentes sigma-robot y actualizar agents.md e id_agente.md 2026-10-17 03:11:03 -05:00
pablinux acd5fdb5d8 docs: registrar app_compartir en MCP infraestructura (ID 34) y agregar id_agente.md 2026-10-17 01:45:28 -05:00
pablinux 7b7b45e767 feat: integrar servicio siax-app-DROP_SIGMAC_APP para SIAX Monitor y actualizar docs de infra 2026-10-14 20:11:07 -05:00
24 changed files with 706 additions and 141 deletions
+14 -6
View File
@@ -8,14 +8,22 @@
## Ideas pendientes ## Ideas pendientes
- **Protección con PIN o contraseña opcional:** Permitir que quien comparte un archivo pueda agregar un PIN de 4 dígitos o contraseña opcional para mayor privacidad al compartir enlaces sensibles. - **Mini editor de texto con syntax highlighting enriquecido:** Editor embebido ligero (CodeMirror o Monaco Editor minificado) para edición o visualización avanzada de código con resaltado de sintaxis antes de compartir.
- **Descargas comprimidas ZIP multi-archivo:** Si un usuario sube un lote de varios archivos a la vez, empaquetarlos en un solo enlace con opción "Descargar todo como ZIP". - **Previsualización de modelos 3D / audio spectrum:** Visualizador simple para archivos GLTF/OBJ o visualizador de espectro interactivo para pistas de audio.
- **Límite de un solo uso (Burn after reading):** Opción para que un archivo o secreto en texto se auto-elimine inmediatamente después de la primera visualización o descarga.
- **Integración con bot del ecosistema (sigma-robot):** Enviar alerta o notificación opcional a un canal cuando un archivo clave haya sido descargado o abierto. ---
## Ideas promovidas a objetivos.md
- [x] **Descargas comprimidas ZIP multi-archivo** → [Objetivo #1](objetivos.md#pendientes)
- [x] **Notificación por bot o webhook al compartir** → [Objetivo #2](objetivos.md#pendientes)
- [x] **Modo P2P / WebRTC para transferir archivos pesados** → [Objetivo #3](objetivos.md#detalle-de-objetivos-pendientes)
- [x] **Widget publicitario del ecosistema (ads.sigmac.app)** → [Objetivo #4](objetivos.md#detalle-de-objetivos-pendientes)
- [x] **Protección con PIN o contraseña opcional** → [Objetivo #5](objetivos.md#detalle-de-objetivos-pendientes)
- [x] **Límite de un solo uso (Burn after reading)** → [Objetivo #6](objetivos.md#detalle-de-objetivos-pendientes)
--- ---
## Ideas en borrador ## Ideas en borrador
- Modo P2P / WebRTC para transferir archivos pesados gigabytes directamente entre navegadores en la misma red local sin almacenarlos en el servidor. - Sincronización de portapapeles en tiempo real entre dispositivos autorizados mediante WebSockets.
- Mini editor de texto con syntax highlighting enriquecido (Monaco Editor o CodeMirror ligero).
+77 -72
View File
@@ -144,7 +144,7 @@ cada proyecto debera implementar un algoritomo de control de versiones de las ac
| **app_fidelizacion** | [pendiente — crear repo en git.telcotronics.net] | Node.js (Express) + MySQL + EJS | pablinux | 🟡 En desarrollo activo | Plataforma de lealtad, escáner QR y canjes. Gestión de clientes y transacciones de partners. Puerto 2001. BD: MySQL `nexo_fd` en 192.168.10.149. | | **app_fidelizacion** | [pendiente — crear repo en git.telcotronics.net] | Node.js (Express) + MySQL + EJS | pablinux | 🟡 En desarrollo activo | Plataforma de lealtad, escáner QR y canjes. Gestión de clientes y transacciones de partners. Puerto 2001. BD: MySQL `nexo_fd` en 192.168.10.149. |
| **api_service_ia** | `git@github.com:telcotronics/API_Service_IA.git` | Python 3.14 + FastAPI + uvicorn | pablinux | 🟡 En desarrollo activo | API REST de modelos de IA preentrenados (OCR, STT, TTS, visión facial, PDF). Único proyecto Python serio del ecosistema. Puerto 8000. BD: MariaDB `api_ia_python` en .149. | | **api_service_ia** | `git@github.com:telcotronics/API_Service_IA.git` | Python 3.14 + FastAPI + uvicorn | pablinux | 🟡 En desarrollo activo | API REST de modelos de IA preentrenados (OCR, STT, TTS, visión facial, PDF). Único proyecto Python serio del ecosistema. Puerto 8000. BD: MariaDB `api_ia_python` en .149. |
| **API_CENTINEL_SECURITY** | `https://git.telcotronics.net/pablinux/API-CENTINEL-SECURITY.git` | Java 17 + Spring Boot 3.3 + WebClient | pablinux | ✅ Activo | API de Gestión de Seguridad Electrónica — control de acceso físico, biometría, apertura remota de puertas, sincronización de credenciales y eventos en tiempo real. Punto único de integración para cualquier app que gestione seguridad física en el ecosistema. | | **API_CENTINEL_SECURITY** | `https://git.telcotronics.net/pablinux/API-CENTINEL-SECURITY.git` | Java 17 + Spring Boot 3.3 + WebClient | pablinux | ✅ Activo | API de Gestión de Seguridad Electrónica — control de acceso físico, biometría, apertura remota de puertas, sincronización de credenciales y eventos en tiempo real. Punto único de integración para cualquier app que gestione seguridad física en el ecosistema. |
| **audio_control** | `https://git.telcotronics.net/pablinux/audio_control.git` | Node.js (Express 4) + MariaDB + DLNA/UPnP + ffplay | pablinux | ✅ Activo / Producción | Backend SoundWave — control remoto de reproducción de audio, descarga YouTube, playlist MySQL, renderer DLNA y auth Google OAuth. Puerto 4005 en CT 132 (`192.168.10.160`). Dominio: `audiocontrol.sigmac.app`. Servicio systemd: `siax-app-AUDIO_CONTROL`. MCP ID: 15. | | **audio_control** | `https://git.telcotronics.net/pablinux/audio_control.git` | Node.js (Express 4) + MariaDB + DLNA/UPnP + ffplay | pablinux | ✅ Activo / Producción | Backend SoundWave — control remoto de reproducción de audio, descarga YouTube, playlist MySQL, renderer DLNA y auth Google OAuth. Puerto 4005 en CT 132 (`192.168.10.160`). Dominio: `musica.sigmac.app`. Servicio systemd: `siax-app-AUDIO_CONTROL`. MCP ID: 15. |
| **SoundWave** | `https://git.telcotronics.net/pablinux/audio-player.git` | Vue 3 + Vite 7 (PWA) / Node.js (Express) + MongoDB | pablinux | 🟢 Activo en producción | Reproductor de música personal PWA. Desplegado en server-webaps (.160) puerto 2005. Auth Google OAuth, streaming con Range requests, descargador YouTube MP3 (yt-dlp) y monitoreado en SIAX Monitor. | | **SoundWave** | `https://git.telcotronics.net/pablinux/audio-player.git` | Vue 3 + Vite 7 (PWA) / Node.js (Express) + MongoDB | pablinux | 🟢 Activo en producción | Reproductor de música personal PWA. Desplegado en server-webaps (.160) puerto 2005. Auth Google OAuth, streaming con Range requests, descargador YouTube MP3 (yt-dlp) y monitoreado en SIAX Monitor. |
| **app_sigma_inventario** (Control Inventario) | [pendiente — git.telcotronics.net] | Flutter (Android / Linux Desktop) / Dart | pablinux | 🟡 En desarrollo activo | App móvil para supervisores y bodegueros: conciliación física de stock, traslados con código de barras y recepción OCR externa. | | **app_sigma_inventario** (Control Inventario) | [pendiente — git.telcotronics.net] | Flutter (Android / Linux Desktop) / Dart | pablinux | 🟡 En desarrollo activo | App móvil para supervisores y bodegueros: conciliación física de stock, traslados con código de barras y recepción OCR externa. |
| **agente_ventas** | [sin repositorio — local] | Flutter 2.11 / Dart 2.17-beta + SQLite | pablinux | 🟡 En desarrollo activo — integrando API real | App "Agente Ventas SIGMAC" — gestión de rutas y pedidos de campo para vendedores de Telcotronics. Ruta del día, catálogo, pedidos, firma digital, scanner QR/barcode, notificaciones in-app. Auth vía API-SIGMA-WEBCONTROL · datos vía API-SIGMA-CLOUD (BD `TELCOTRONICS`). | | **agente_ventas** | [sin repositorio — local] | Flutter 2.11 / Dart 2.17-beta + SQLite | pablinux | 🟡 En desarrollo activo — integrando API real | App "Agente Ventas SIGMAC" — gestión de rutas y pedidos de campo para vendedores de Telcotronics. Ruta del día, catálogo, pedidos, firma digital, scanner QR/barcode, notificaciones in-app. Auth vía API-SIGMA-WEBCONTROL · datos vía API-SIGMA-CLOUD (BD `TELCOTRONICS`). |
@@ -153,8 +153,8 @@ cada proyecto debera implementar un algoritomo de control de versiones de las ac
| **API-SIGMA-COMUNICACIONES** | `https://git.telcotronics.net/pablinux/API-SIGMA-COMUNICACIONES.git` | Node.js (Express) + MySQL | pablinux | 🔴 En desarrollo inicial | Gateway SaaS multi-tenant de canales de mensajería: cada cliente/organización crea y conecta su propio componente WhatsApp (bot o Meta), Telegram y redes sociales, aislado del resto. Independiente de `sigma-robot` (comunicaciones internas de Telcotronics). | | **API-SIGMA-COMUNICACIONES** | `https://git.telcotronics.net/pablinux/API-SIGMA-COMUNICACIONES.git` | Node.js (Express) + MySQL | pablinux | 🔴 En desarrollo inicial | Gateway SaaS multi-tenant de canales de mensajería: cada cliente/organización crea y conecta su propio componente WhatsApp (bot o Meta), Telegram y redes sociales, aislado del resto. Independiente de `sigma-robot` (comunicaciones internas de Telcotronics). |
| **MCP-Infraestructura** | `https://git.telcotronics.net/pablinux/MCP-INFRAESTRUCTURA.git` | TypeScript (@modelcontextprotocol/sdk) + Nuxt 3 + MySQL | pablinux | ✅ Activo | Servidor MCP y panel web para inventario y gestión en tiempo real de la infraestructura del ecosistema (hardware, servicios, apps IA y externos). Fuente de verdad en MySQL. | | **MCP-Infraestructura** | `https://git.telcotronics.net/pablinux/MCP-INFRAESTRUCTURA.git` | TypeScript (@modelcontextprotocol/sdk) + Nuxt 3 + MySQL | pablinux | ✅ Activo | Servidor MCP y panel web para inventario y gestión en tiempo real de la infraestructura del ecosistema (hardware, servicios, apps IA y externos). Fuente de verdad en MySQL. |
| **proxy_server_SRI** | `https://git.telcotronics.net/pablinux/proxy_server_SRI.git` | Python 3 (ThreadingHTTPServer + requests) | pablinux | ✅ Producción | Script proxy HTTP multihilo para consultas SRI en cascada de RUC y Cédula (Ecuador). Provee proxy y normalización para WebControl, SIGMAC y apps. | | **proxy_server_SRI** | `https://git.telcotronics.net/pablinux/proxy_server_SRI.git` | Python 3 (ThreadingHTTPServer + requests) | pablinux | ✅ Producción | Script proxy HTTP multihilo para consultas SRI en cascada de RUC y Cédula (Ecuador). Provee proxy y normalización para WebControl, SIGMAC y apps. |
| **cloud-sync** | `https://git.telcotronics.net/pablinux/Service-Cloud-SINC.git` | Rust 2021 + Axum 0.7 + SQLite | pablinux | 🟡 En mantenimiento / primer deploy | Servidor central de backup cifrado y consolas web. Puerto 3000 en 192.168.10.136. MCP ID: 12. | | **cloud-sync** | `https://git.telcotronics.net/pablinux/Service-Cloud-SINC.git` | Rust 2021 + Axum 0.7 + SQLite | pablinux | ✅ Activo / Producción HTTP | Servidor central de backup cifrado y consolas web. `192.168.10.136:3000`, health `ok` y harness remoto upload/list/download/restore verificados el 2026-10-17. HTTPS pendiente; MCP id 12. |
| **cloud-sync-clients** | [sin remoto aún — siax-amd] | Rust 2021 + Axum 0.7 + Tokio + aes-gcm + zstd | pablinux | 🟡 En desarrollo activo | Clientes server-to-server (Linux/Windows) para respaldo y cifrado local hacia cloud-sync. UI local :3001. MCP ID: 21. | | **cloud-sync-clients** | [sin remoto aún — siax-amd] | Rust 2021 + Axum 0.7 + Tokio + aes-gcm + zstd + rusqlite | pablinux | 🟡 Operativo / En desarrollo | Clientes server-to-server (Linux/Windows) para respaldo y cifrado local hacia cloud-sync. UI local :3001. Harness remoto validado (192.168.10.136:3000). MCP ID: 21. Agente ID: 42. |
--- ---
@@ -1340,10 +1340,10 @@ Aplicación web en Go para transferencia inmediata de archivos, fotos, documento
| Responsable | pablinux | | Responsable | pablinux |
| Estado actual | ✅ Operativo / En pruebas | | Estado actual | ✅ Operativo / En pruebas |
| Ubicación local | `siax-amd` — `/home/pablinux/Projects/GO/app_compartir` | | Ubicación local | `siax-amd` — `/home/pablinux/Projects/GO/app_compartir` |
| Servidor de producción | `server-webapps` CT 132 (`192.168.10.160`) — pendiente deploy | | Servidor de producción | `server-webapps` CT 132 (`192.168.10.160`) |
| Dominio público | `drop.sigmac.app` | | Dominio público | `drop.sigmac.app` |
| Puerto | `2006` | | Puerto | `2008` |
| Servicio systemd | `app-compartir.service` | | Servicio systemd | `siax-app-DROP_SIGMAC_APP.service` (gestionado por SIAX Monitor) |
**Bases de Datos:** **Bases de Datos:**
* **SQLite** (`data/compartir.db` local en modo WAL): Almacena metadatos de archivos compartidos (`shares`), usuarios vinculados (`users`) y tokens de sesión (`sessions`). * **SQLite** (`data/compartir.db` local en modo WAL): Almacena metadatos de archivos compartidos (`shares`), usuarios vinculados (`users`) y tokens de sesión (`sessions`).
@@ -1456,7 +1456,7 @@ Backend de la app **SoundWave**. Permite controlar la reproducción de audio de
| Estado actual | ✅ Activo / Desplegado en producción | | Estado actual | ✅ Activo / Desplegado en producción |
| Equipo / ubicación local | `siax-amd` (`192.168.10.100`) — `/home/pablinux/Projects/Node/audio_control` | | Equipo / ubicación local | `siax-amd` (`192.168.10.100`) — `/home/pablinux/Projects/Node/audio_control` |
| Servidor de producción | `server-webaps` CT 132 (`192.168.10.160`) — `/home/user_apps/apps/audio_control` | | Servidor de producción | `server-webaps` CT 132 (`192.168.10.160`) — `/home/user_apps/apps/audio_control` |
| Dominio público | `audiocontrol.sigmac.app` (vhost activo en .160; enrutamiento WAN sujeto a proxy en .109 / NAT) | | Dominio público | `musica.sigmac.app` (vhost activo en .160; enrutamiento WAN sujeto a proxy en .109 / NAT) |
| Puerto | `4005` (dev: `4000`) | | Puerto | `4005` (dev: `4000`) |
| Servicio systemd | `siax-app-AUDIO_CONTROL.service` (activo) | | Servicio systemd | `siax-app-AUDIO_CONTROL.service` (activo) |
| Registro MCP | Servicio ID `15` en `http://192.168.10.160:3006` | | Registro MCP | Servicio ID `15` en `http://192.168.10.160:3006` |
@@ -2410,21 +2410,25 @@ SIAX es la inteligencia artificial del ecosistema. Aprende de forma autónoma y
## api_service_ia — API de Servicios con IA ## api_service_ia — API de Servicios con IA
Microservicio REST que centraliza modelos de IA preentrenados para consumo interno del ecosistema. Es el **único proyecto Python serio de Telcotronics**: todos los demás son Node.js, Java, PHP, Rust o Flutter. Expone capacidades de procesamiento pesado (Whisper, InsightFace, Silero, rembg) como endpoints HTTP autenticados, evitando duplicar dependencias en cada proyecto que las necesite. Actualmente consumido por `sigma-robot` para STT y OCR. Microservicio REST que centraliza modelos de IA preentrenados para consumo interno del ecosistema. Es el **único proyecto Python serio de Telcotronics**: todos los demás son Node.js, Java, PHP, Rust o Flutter. Expone capacidades de procesamiento pesado (Whisper, InsightFace, Silero, rembg) como endpoints HTTP autenticados, evitando duplicar dependencias en cada proyecto que las necesite. Actualmente consumido por `sigma-robot` para STT y OCR. Requiere GPU NVIDIA: Whisper corre en CUDA sin fallback a CPU, por decisión de diseño.
| Parámetro | Valor | | Parámetro | Valor |
|-----------|-------| |-----------|-------|
| Repositorio Git | `git@github.com:telcotronics/API_Service_IA.git` | | Repositorio Git | `git@github.com:telcotronics/API_Service_IA.git` |
| Tecnología principal | Python 3.14 + FastAPI + uvicorn | | Tecnología principal | Python 3.14 + FastAPI + uvicorn |
| Responsable | pablinux | | Responsable | pablinux |
| Estado actual | ✅ Producción | | Estado actual | ✅ Producción (verificado en vivo 2026-10-17) |
| Código local | `siax-amd:/home/pablinux/Projects/Python/api_service_ia/` | | Código local | `siax-intel:/home/pablinux/Projects/Python/api_service_ia/` |
| Servidor producción | `Ubuntu-Docker` — CT 105 (`192.168.10.145`) — usuario `root` | | Servidor producción | `APPS-SERVICE-IA` — CT 140, nodo cluster (`192.168.10.154`) — usuario `pablinux` — GPU RTX 5060 8 GB |
| Ruta en servidor | `/root/app/API_Service_IA` | | Ruta en servidor | `/home/pablinux/apps/API_Service_IA` (venv `api_env/`, Python 3.12.3) |
| Dominio público | `api.telcotronics.net` (`whisper.telcotronics.net` — legacy, obsoleto) | | Dominio público | `https://api.telcotronics.net` vía Nginx Proxy Manager .141 (`whisper.telcotronics.net` — legacy, obsoleto) |
| Swagger | `https://api.telcotronics.net/docs` |
| Puerto | `8000` | | Puerto | `8000` |
| Servicio de arranque | `tmux` — sesión `api_service_ia` (pendiente migrar a systemd) | | Servicio de arranque | `tmux` — hoy en la sesión `ia-services` (`desplegar.sh` usa `api_service_ia`; pendiente unificar o migrar a systemd) |
| Última actualización | 2026-06-03 | | Servidor anterior | `192.168.10.145` — ya no sirve la API (puerto 8000 cerrado) |
| MCP de Infraestructura | App IA id 2 `api_service_ia` · hardware id 12 `CT 140 APPS-SERVICE-IA` · agente id 5 |
| Agente en sigma-robot | `Agente API Service IA` — ID 85 |
| Última actualización | 2026-10-19 |
**BD que usa:** **BD que usa:**
@@ -2443,20 +2447,20 @@ Microservicio REST que centraliza modelos de IA preentrenados para consumo inter
| Remover fondo | `POST /removerFondo_img/` | PNG con transparencia | ✅ | | Remover fondo | `POST /removerFondo_img/` | PNG con transparencia | ✅ |
| PDF a texto | `POST /convertir_pdf_aTexto/` | JSON `{texto}` | ✅ | | PDF a texto | `POST /convertir_pdf_aTexto/` | JSON `{texto}` | ✅ |
| PDF a Word | `POST /convertir_pdf_aWord/` | `.docx` descargable | ✅ | | PDF a Word | `POST /convertir_pdf_aWord/` | `.docx` descargable | ✅ |
| PDF a Excel | `POST /convertir_pdf_aExcel/` | `.xlsx` descargable | ✅ | | PDF a Excel | `POST /convertir_pdf_aExcel/` | `.xlsx` descargable | ❌ en producción (dependencia `tabula` equivocada); corregido en el repo, pendiente de desplegar |
| PDF tablas a JSON | `POST /pdf_tablas/` | JSON estructurado | ✅ | | PDF tablas a JSON | `POST /pdf_tablas/` | JSON estructurado | ✅ |
| Reconocimiento facial | `POST /facial/detectar/` | JSON `{bbox, confianza}` | ✅ | | Reconocimiento facial | `POST /facial/detectar/` | JSON `{bbox, confianza}` | ✅ |
| Comparación facial | `POST /facial/comparar/` | JSON `{es_misma_persona, similitud}` | ✅ | | Comparación facial | `POST /facial/comparar/` | JSON `{es_misma_persona, similitud}` | ✅ |
| TTS online (gTTS) | `POST /texto_aVoz/` | MP3 descargable | ✅ requiere internet | | TTS online (gTTS) | `POST /texto_aVoz/` | MP3 descargable | ✅ requiere internet |
| TTS offline (Silero) | `POST /texto_aVoz/silero/` | WAV 24kHz descargable | ✅ offline tras 1ª descarga | | TTS offline (Silero) | `POST /texto_aVoz/silero/` | WAV 16 kHz descargable | ⚠️ en producción el audio sale truncado; corregido en el repo, pendiente de desplegar |
**Autenticación:** header `X-API-Key` — validado contra `api_ia_python.api_key` en MariaDB .149. **Autenticación:** header `X-API-Key` — validado contra `api_ia_python.api_key` en MariaDB .149.
**Integración con el ecosistema:** **Integración con el ecosistema:**
- **sigma-robot** la consume para STT (`/convertir_audio_aTexto/`) y OCR/imágenes (`https://api.telcotronics.net`) - **sigma-robot** la consume para STT (`/convertir_audio_aTexto/`) y OCR/imágenes — debe usar `https://api.telcotronics.net`, no `192.168.10.145:8000`
- Cualquier proyecto del ecosistema puede consumirla con una API key válida - Cualquier proyecto del ecosistema puede consumirla con una API key válida
**Dónde buscar más info:** `siax-amd:/home/pablinux/Projects/Python/api_service_ia/agents.md` **Dónde buscar más info:** `siax-intel:/home/pablinux/Projects/Python/api_service_ia/agents.md`
--- ---
@@ -2561,74 +2565,75 @@ curl -X POST https://api.telcotronics.com/api/biometria/1001 \
## cloud-sync — Sistema de Backup Automático y Recuperación ante Desastre ## cloud-sync — Sistema de Backup Automático y Recuperación ante Desastre
cloud-sync es el servidor central de backup y recuperación ante desastre para clientes SIGMA. El agente de origen comprime y cifra archivos y dumps de SQLite, MySQL, MariaDB o bases compatibles antes de subirlos; el servidor almacena metadatos y contenido cifrado, sin recibir la clave del cliente. El repositorio incluye la API Rust y las consolas root/empresa; los ejecutables server-to-server viven en `cloud-sync-clients`. La integración Flutter/Java y la aplicación de escritorio siguen siendo objetivos posteriores. cloud-sync es un servidor central de backup y recuperación ante desastre para clientes SIGMA. Los datos se comprimen y cifran en el equipo de origen antes de subirlos; el servidor almacena contenido cifrado y metadatos, sin recibir la clave de cifrado. El repositorio mantiene la API Rust y las consolas root/empresa. Los ejecutables server-to-server están en el proyecto separado `cloud-sync-clients`; Tauri y los SDK Flutter/Java siguen pendientes.
| Parámetro | Valor | | Parámetro | Valor |
|---|---| |---|---|
| Repositorio Git | `https://git.telcotronics.net/pablinux/Service-Cloud-SINC.git` (privado, rama `main`, último commit documentado `babf1cd`) | | Repositorio Git | `https://git.telcotronics.net/pablinux/Service-Cloud-SINC.git` (privado, rama `main`) |
| Tecnología principal | Rust 2021 · Axum 0.7 · Tokio · rusqlite/SQLite · filesystem local · HTML/CSS/JavaScript para consolas web | | Tecnología principal | Rust 2021 · Axum 0.7 · Tokio · rusqlite/SQLite · filesystem local · HTML/CSS/JavaScript |
| Responsable | pablinux | | Responsable | pablinux |
| Estado actual | 🟡 Primer despliegue y smoke test HTTP aprobados; HTTPS público, auth Cloud dual y pruebas funcionales pendientes | | MCP de Infraestructura | Servicio id 12 · categoría `service` · estado `ACTIVE` |
| Equipo / código local | `siax-amd` (`192.168.10.100`) — `/home/pablinux/Projects/Rust/cloud monitor sinc` | | Estado operativo | Producción HTTP. El 2026-10-17 `/health` respondió HTTP 200, `status: ok`, versión `0.1.0`; harness remoto aislado completó upload/list/download/restore desde `cloud-sync-clients` |
| Servidor de producción | `192.168.10.136` — `/home/user_apps/apps/cloud-sync`; tmux activo, `/health` y consolas HTTP 200 verificados 2026-09-21 | | Servidor de producción | `192.168.10.136:3000`; ruta documentada `/home/user_apps/apps/cloud-sync` |
| Dominio público | Pendiente — VirtualHost HTTPS en Apache | | Hardware / CT | No hay entidad correspondiente a `192.168.10.136` en `infra://hardware`; sin CT confirmado. Feedback MISSING id 24, abierto el 2026-10-17 |
| Puerto interno | `3000` | | Dominio público / HTTPS | Sin dominio confirmado; HTTPS público pendiente |
| Última actualización | 2026-09-30 | | Feedback MCP | Cero reportes al iniciar la revisión del 2026-10-17; se abrió después el MISSING id 24 por la ficha de hardware faltante |
| Reglas de despliegue | Ninguna activa devuelta para alcance `cloud-sync` ni global. Hay una regla global SRI en borrador, no aplicable a este servicio |
| Última actualización | 2026-10-17 |
**BD que usa:** **Almacenamiento de datos:**
| Motor | Host | Nombre | Uso | | Motor | Host / ruta | Uso |
|---|---|---|---| |---|---|---|
| SQLite (embebida, bundled) | `192.168.10.136` — `/home/user_apps/apps/cloud-sync/data` | `server.db` | Empresas, cuotas, tokens, perfiles, sesiones, backups (metadata) y eventos | | SQLite embebida | `192.168.10.136` — `/home/user_apps/apps/cloud-sync/data/server.db` | Empresas, cuotas, perfiles, sesiones, metadatos de backups y eventos |
| SQLite (embebida, en el cliente) | Equipo de origen | `index.db` | Índice local de rutas, checksum SHA-256, backup_id y timestamps | | SQLite local del cliente | Equipo de origen — `index.db` | Rutas, checksum SHA-256, identificadores y timestamps de backups |
| Filesystem | Servidor `192.168.10.136` | Contenido cifrado de los backups, organizado por empresa |
**Servicios que consume y expone:** **Servicios que consume y expone:**
| Método | Endpoint | Auth | Descripción | | Método | Endpoint | Auth | Descripción |
|---|---|---|---| |---|---|---|---|
| GET | `/health` | — | Estado del servidor + info de disco | | GET | `/health` | — | Estado del servidor y capacidad de disco |
| POST | `/auth/token` | — | Login cliente (token UUID) → sesión Bearer | | POST | `/auth/token` | Token de empresa | Compatibilidad con agentes integradores |
| POST | `/auth/admin` | — | Login admin (argon2) → session token | | POST | `/auth/root`, `/auth/admin` | Usuario y contraseña | Login root; `/auth/admin` es alias compatible |
| POST | `/backup/upload` | Bearer token | Subir archivo cifrado (multipart) | | POST | `/auth/empresa` | Usuario y contraseña | Login de administrador de empresa |
| GET | `/backup/list` | Bearer token | Listar backups de la empresa | | POST | `/auth/logout` | Sesión Bearer | Revocar la sesión presentada |
| GET | `/backup/download/{id}` | Bearer token | Descargar backup para restore | | PUT | `/auth/admin/password` | Sesión root | Cambiar contraseña root |
| DELETE | `/backup/{id}` | Bearer token | Eliminar backup | | PUT | `/auth/empresa/password` | Sesión empresa | Cambiar contraseña de empresa |
| GET | `/me/storage` | Bearer token | Uso actual vs cuota asignada | | GET | `/empresa/cuenta` | Sesión empresa | Consultar su cuenta y perfil |
| GET | `/admin/storage` | X-Admin-Token | Capacidad CT146 + resumen global | | POST | `/backup/upload` | Bearer de integración | Subir backup cifrado multipart; límite configurado de hasta 10 GiB y cuota por empresa |
| GET/POST | `/admin/clientes` | X-Admin-Token | Listar / crear empresas | | GET | `/backup/list`, `/backup/status` | Bearer de integración | Listar respaldos y consultar estado |
| PUT | `/admin/clientes/{id}/cuota` | X-Admin-Token | Ajustar cuota por empresa | | GET | `/backup/download/{id}` | Bearer de integración o sesión empresa | Descargar respaldo cifrado propio |
| GET | `/admin/eventos` | X-Admin-Token | Log de auditoría | | DELETE | `/backup/{id}` | Bearer de integración | Eliminar backup propio |
| GET | `/root/` | — | Consola root para empresas, cuotas, estados, perfiles y accesos | | GET | `/me/storage` | Bearer de integración | Uso y cuota de empresa |
| GET | `/admin/` | — | Portal admin de empresa para consultar cuenta y descargar respaldos propios | | GET | `/admin/storage`, `/admin/clientes`, `/admin/eventos` | Sesión root | Capacidad, empresas y auditoría |
| GET | `/panel/` | Token de integración | Portal legado de cliente | | POST | `/admin/clientes` | Sesión root | Crear empresa y token de integración |
| MCP Infraestructura | `http://192.168.10.160:3006/sse` | Uso interno del ecosistema | Inventario; `cloud-sync` registrado como servicio id 12; `cloud-sync-clients` registrado como servicio id 21. No transporta errores de runtime | | PUT | `/admin/clientes/{id}/cuota`, `/estado` | Sesión root | Cambiar cuota o suspender empresa |
| API-SIGMA-WEBCONTROL | `https://api.siax-system.net/api/errores` | `x-api-key` por aplicación | Integración de bitácora de errores pendiente; no hay clave configurada | | GET/PUT | `/admin/clientes/{id}/perfil` | Sesión root | Consultar o editar perfil |
| PUT | `/admin/clientes/{id}/acceso` | Sesión root | Asignar o reemplazar acceso de empresa |
| GET | `/root/`, `/admin/`, `/panel/` | Según consola | Root, administrador de empresa y portal legado |
**Módulos disponibles:** **Estado de módulos y pendientes:**
| Módulo | Estado | | Módulo / tarea | Estado |
|---|---| |---|---|
| Servidor API REST (Axum) | ✅ Completo y probado | | API Rust y consola root | Implementadas y desplegadas; health HTTP verificado |
| Consola web admin (`/admin`) | ✅ Completa | | Consola de empresa | Implementada; validar login y flujos de consola en producción |
| Consola web panel cliente (`/panel`) | ✅ Completa | | Portal `/panel/` | Legado por token de integración |
| `cloud_sync_core` (librería Rust) — crypto, uploader, backup_engine, restore | ✅ Completo | | `cloud-sync-clients` | Proyecto separado, MCP id 21; harness aislado upload/list/download/restore pasó contra `192.168.10.136:3000` el 2026-10-17; Windows pendiente de validación funcional |
| Agente server-to-server (`cloud-sync-clients`) — archivos y dumps | ✅ Base Linux; UI local :3001; harness local/remoto; MCP ID 21; Windows pendiente de validación real | | Autenticación dual | Diseño aprobado; falta cerrar proveedor/login, tokens y registro/revocación de instalaciones |
| Script de despliegue configurable | ✅ Preparado para `192.168.10.136` | | Uploads reanudables y cola durable | Objetivo 10, pendiente de diseño e implementación |
| App desktop (Tauri — Windows/Linux/macOS) | ⏳ Pendiente | | Restauración automatizada y verificada | Objetivo 11; el harness validó un ciclo básico remoto, la automatización de archivos/dumps sigue pendiente |
| SDK Flutter (uniffi-rs → Dart FFI) | ⏳ Pendiente | | HTTPS público | Pendiente confirmar dominio y configurar la entrada aprobada |
| SDK Java (uniffi-rs → JNI) | ⏳ Pendiente | | Bitácora WebControl | Objetivo 8; bloqueada hasta confirmar `app_origen` y obtener `x-api-key` autorizada |
| Deploy en `192.168.10.136` | ✅ Ejecutado; smoke test HTTP aprobado | | App de escritorio Tauri / SDK Flutter / SDK Java | Pendientes |
| HTTPS público detrás de Apache | ⏳ Pendiente de configurar y verificar |
| Bitácora centralizada de errores | ⏳ Pendiente de clave, reportador y consulta operativa |
| Autenticación dual para apps y servicios | ⏳ Diseño aprobado; login Cloud, sesiones cortas y credencial por instalación pendientes |
**Integración con el ecosistema:** **Integración y separación de sistemas:**
- **SIGMAC** (Java ERP, CT 141): SDK Java pendiente — backup automático de archivos y BD de las empresas clientes - **MCP de Infraestructura** (`192.168.10.160:3006`): inventario y reglas operativas. Ficha de servicio id 12; no es proxy de errores de runtime.
- **sigmac_app** (Flutter, `.72`): SDK Flutter pendiente — backup de datos del app sin intervención del usuario - **Feedback MCP:** el 2026-10-17 se reportó MISSING id 24 porque el inventario no contiene una entidad de hardware para `192.168.10.136`. No registrar un CT o ubicación hasta confirmarlos.
- **MCP de Infraestructura** (`192.168.10.160:3006`): inventario actualizado; no es proxy de la bitácora de errores - **API-SIGMA-WEBCONTROL** (`https://api.siax-system.net/api/errores`): destino separado para errores de runtime. No hay `x-api-key` autorizada ni `app_origen` confirmado en este proyecto; la ausencia de consulta no significa ausencia de errores.
- **API-SIGMA-WEBCONTROL**: canal previsto para reportar/consultar errores de runtime cuando exista una clave autorizada - **Reglas de despliegue:** no se devolvieron reglas activas globales ni para `cloud-sync`; no inferir dominio, DNS, ruta pública o contenedor.
- **Autenticación Cloud**: diseño aprobado para login de apps con access/refresh token y credencial protegida por instalación en servicios automáticos; implementación pendiente - **Autenticación Cloud:** la implementación dual sigue pendiente de cerrar el contrato con el proveedor autorizado. No persistir contraseñas Cloud en cloud-sync.
- **Apache**: VirtualHost HTTPS pendiente
**Dónde buscar más información:** `siax-amd:/home/pablinux/Projects/Rust/cloud monitor sinc/agents.md`; cliente server-to-server: `/home/pablinux/Projects/Rust/cloud-sync-clients/agents.md` **Dónde buscar más información:** `siax-amd:/home/pablinux/Projects/Rust/cloud monitor sinc/agents.md`; cliente server-to-server: `/home/pablinux/Projects/Rust/cloud-sync-clients/agents.md`
+43
View File
@@ -13,6 +13,43 @@
|---|----------|--------|-----------| |---|----------|--------|-----------|
| 1 | Soporte para compresión zip en descargas multi-archivo | pablinux | Media | | 1 | Soporte para compresión zip en descargas multi-archivo | pablinux | Media |
| 2 | Notificación opcional por bot o webhook al compartir | pablinux | Baja | | 2 | Notificación opcional por bot o webhook al compartir | pablinux | Baja |
| 3 | Transferencia directa P2P navegador a navegador (WebRTC) | pablinux | Media |
| 4 | Widget publicitario del ecosistema (ads.sigmac.app) en vistas de invitados | pablinux | Baja |
| 5 | Protección por PIN / Contraseña opcional en enlaces compartidos | pablinux | Media |
| 6 | Modo de un solo uso (Burn after reading) con autodestrucción inmediata | pablinux | Media |
---
### Detalle de Objetivos Pendientes
#### 🎯 Objetivo 3: Transferencia directa P2P navegador a navegador (WebRTC)
- **Qué debe cumplirse:**
1. Permitir la transferencia directa de archivos de gran volumen (cientos de MB o varios GB) directamente entre dispositivos sin almacenar el archivo en el disco del servidor.
2. Implementar un servidor de señalización WebRTC ultraligero en Go (vía WebSocket o SSE/HTTP POST) para el intercambio de ofertas, respuestas y candidatos ICE entre emisor y receptor.
3. Transmisión de datos mediante `RTCDataChannel` cifrado punto a punto en el navegador.
4. Integración fluida con el flujo actual: el emisor abre la sala, se genera un enlace/QR dinámico, el receptor lo abre en su navegador y comienza la transferencia directa.
5. Interfaz con barra de progreso bidireccional, velocidad de transferencia y estado de conexión (esperando receptor, conectado, transfiriendo, completado).
6. Si no hay conexión P2P directa (NAT simétrico estricto), informar claramente al usuario o requerir conexión en la misma red local / STUN básico.
#### 🎯 Objetivo 4: Widget publicitario del ecosistema (ads.sigmac.app)
- **Qué debe cumplirse:**
1. Integrar banners o anuncios contextuales no intrusivos provenientes de `ads.sigmac.app` exclusivamente en las vistas públicas de usuarios invitados (Guest): página principal, visor `/v/{id}` y página de descarga.
2. Los usuarios autenticados (WebControl / Google OAuth) en `/mis-archivos` y sus visores estarán 100% libres de publicidad.
3. Carga asíncrona desacoplada: el widget no debe demorar la carga de la página, la previsualización ni la descarga del archivo. Si el servicio de anuncios no responde o falla, el contenedor se oculta limpiamente sin alterar la UI.
4. Respetar las políticas de seguridad estrictas vigentes (CSP, sandbox, aislamiento contra XSS).
5. Diseño integrado al tema oscuro (dark mode) del proyecto, sin popups ni redirecciones invasivas.
#### 🎯 Objetivo 5: Protección por PIN / Contraseña opcional
- **Qué debe cumplirse:**
1. Permitir al creador del share definir un PIN numérico (4-6 dígitos) o contraseña alocada al subir archivo o texto.
2. El visor `/v/{id}`, descarga `/d/{id}` y raw `/raw/{id}` deben solicitar el PIN antes de entregar o previsualizar el contenido.
3. Almacenamiento seguro del hash del PIN en SQLite (bcrypt / argon2) sin almacenar texto claro.
#### 🎯 Objetivo 6: Modo de un solo uso (Burn after reading)
- **Qué debe cumplirse:**
1. Opción al subir para marcar el contenido como "Auto-destrucción tras lectura / descarga".
2. Tras la primera visualización exitosa o descarga completa, el archivo físico se purga de inmediato del disco y el registro se marca como destruido o eliminado en SQLite.
3. Intentos posteriores de acceso redirigen a una vista informativa indicando que el archivo ya fue destruido.
--- ---
@@ -36,3 +73,9 @@
| 2026-10-13 | Sesión Guest con auto-eliminación obligatoria en 24h (física y BD) | Worker periódico de purga en segundo plano verificado con tests | | 2026-10-13 | Sesión Guest con auto-eliminación obligatoria en 24h (física y BD) | Worker periódico de purga en segundo plano verificado con tests |
| 2026-10-13 | Cuentas registradas (Google y WebControl) con almacenamiento permanente | Cuentas no-guest exentas de borrado a las 24h | | 2026-10-13 | Cuentas registradas (Google y WebControl) con almacenamiento permanente | Cuentas no-guest exentas de borrado a las 24h |
| 2026-10-13 | Panel / lista de "Mis Archivos" para usuarios registrados con opción de borrado | Interfaz `/mis-archivos` con métricas de visitas y eliminación | | 2026-10-13 | Panel / lista de "Mis Archivos" para usuarios registrados con opción de borrado | Interfaz `/mis-archivos` con métricas de visitas y eliminación |
| 2026-10-14 | Scripts de despliegue estándar (`desplegar.sh`, `init.sh`) y servicio para SIAX Monitor | Compilación Go estática, scp, servers.conf y systemd |
| 2026-10-17 | Registro oficial en MCP Infraestructura (ID 34) | Ficha técnica completa registrada en MariaDB bajo categoría application |
| 2026-10-17 | Registro en centro de comunicaciones de agentes (sigma-robot) | Identidad `Agente drop.sigmac.app` registrada vía REST; credenciales en `.env` |
| 2026-10-17 | Sincronización de normas y archivos base del ecosistema | Creación de `id_agente.md`, `reglas.md`, `tareas.md` y espejo de `infraestructura.md` |
| 2026-10-19 | Despliegue en producción en CT 132 con SIAX Monitor (:8080) | Servicio `siax-app-DROP_SIGMAC_APP.service` operativo en puerto 2008 |
| 2026-10-20 | Puesta en producción pública vía HTTPS en drop.sigmac.app | Proxy Apache con SSL operativo, URLs y QR dinámicos con protocolo HTTPS verificado |
+10 -1
View File
@@ -15,7 +15,9 @@ app_compartir/
│ ├── objetivos.md │ ├── objetivos.md
│ ├── proyecto_errores.md │ ├── proyecto_errores.md
│ ├── proyecto_estructura.md │ ├── proyecto_estructura.md
│ └── proyecto_memoria.md │ ├── proyecto_memoria.md
│ ├── reglas.md
│ └── tareas.md
├── internal/ ├── internal/
│ ├── auth/ │ ├── auth/
│ │ └── auth.go # Manejo de sesiones, WebControl y Google OAuth2 │ │ └── auth.go # Manejo de sesiones, WebControl y Google OAuth2
@@ -32,6 +34,11 @@ app_compartir/
│ └── storage/ │ └── storage/
│ └── storage.go # Slugs aleatorios, sniffing MIME y guardado en disco │ └── storage.go # Slugs aleatorios, sniffing MIME y guardado en disco
├── web/ ├── web/
│ ├── static/ # Iconos, favicons y recursos estáticos de la marca
│ │ ├── favicon.ico # Icono multirresolución para navegadores
│ │ ├── favicon.svg # Icono vectorial escalable y moderno
│ │ ├── icon-192.png # Icono PWA / accesos directos móviles
│ │ └── icon-512.png # Icono alta resolución / splash screen
│ └── templates/ │ └── templates/
│ ├── base.html # Layout común con Tailwind CSS y FontAwesome │ ├── base.html # Layout común con Tailwind CSS y FontAwesome
│ ├── expired.html # Mensaje informativo de archivo guest caducado (24h) │ ├── expired.html # Mensaje informativo de archivo guest caducado (24h)
@@ -42,8 +49,10 @@ app_compartir/
├── .env.example ├── .env.example
├── .gitignore ├── .gitignore
├── desplegar.sh # Script de compilación y despliegue (máquina dev) ├── desplegar.sh # Script de compilación y despliegue (máquina dev)
├── id_agente.md # Identidad oficial del agente en el ecosistema
├── init.sh # Script ejecutor local en el servidor ├── init.sh # Script ejecutor local en el servidor
├── servers.conf.example # Plantilla de credenciales SSH para despliegue ├── servers.conf.example # Plantilla de credenciales SSH para despliegue
├── siax-app-DROP_SIGMAC_APP.service # Definición de servicio systemd para SIAX Monitor
├── go.mod ├── go.mod
├── go.sum ├── go.sum
├── main.go # Punto de entrada y servidor HTTP Go ├── main.go # Punto de entrada y servidor HTTP Go
+17 -1
View File
@@ -16,6 +16,12 @@
| 2026-10-13 | Generación de QR nativa en Go vía `/qr/{id}` | Se utiliza `github.com/skip2/go-qrcode` para servir el QR directamente en formato PNG (256x256), garantizando compatibilidad total con cualquier cámara de smartphone sin depender de scripts cliente pesados. | | 2026-10-13 | Generación de QR nativa en Go vía `/qr/{id}` | Se utiliza `github.com/skip2/go-qrcode` para servir el QR directamente en formato PNG (256x256), garantizando compatibilidad total con cualquier cámara de smartphone sin depender de scripts cliente pesados. |
| 2026-10-13 | Soporte doble de login: WebControl corporativo + Google OAuth | Brinda flexibilidad tanto para colaboradores del ecosistema Telcotronics (vía `api.siax-system.net`) como para usuarios externos con Google. | | 2026-10-13 | Soporte doble de login: WebControl corporativo + Google OAuth | Brinda flexibilidad tanto para colaboradores del ecosistema Telcotronics (vía `api.siax-system.net`) como para usuarios externos con Google. |
| 2026-10-14 | Adopción de la marca y dominio `drop.sigmac.app` | Nombre conciso, memorable y alineado con los servicios y subdominios del ecosistema SIGMA (sigmac.app). | | 2026-10-14 | Adopción de la marca y dominio `drop.sigmac.app` | Nombre conciso, memorable y alineado con los servicios y subdominios del ecosistema SIGMA (sigmac.app). |
| 2026-10-17 | Registro oficial en MCP Infraestructura (ID 34) e identidad de agente | Se vinculó el proyecto al inventario central MariaDB vía API REST (:3007), asignando ID 34 bajo categoría application, y se creó `id_agente.md` según el estándar de identidad del ecosistema. |
| 2026-10-19 | Despliegue en producción en CT 132 con supervisión SIAX Monitor | Se desplegó en `server-webapps`. Registrado en SIAX Monitor (:8080) como `siax-app-DROP_SIGMAC_APP.service`, habilitando reinicio atómico vía API sin sudo. |
| 2026-10-20 | Reasignación de puerto a 2008 para liberar 2006 a audio_control | Se acordó con pablinux liberar el puerto 2006 para `audio_control` (correlativo a SoundWave en 2005) y trasladar `drop.sigmac.app` al puerto 2008 en CT 132 y MCP Infraestructura (ID 34). |
| 2026-10-20 | Activación de dominio público https://drop.sigmac.app | Pablinux configuró el proxy reverso Apache en CT 150 con SSL Let's Encrypt. Se optimizó `getBaseURL()` para forzar HTTPS en los enlaces y códigos QR generados cuando el Host es `drop.sigmac.app`. |
| 2026-10-20 | Identidad visual e iconos multi-formato (SVG, ICO, PNG) | Se diseñó un icono SVG escalable con flecha bidireccional y pulsos de transferencia en colores esmeralda/cian sobre contenedor squircle grafito oscuro. Se generaron versiones PNG (64, 192, 512 px) e ICO multi-resolución, enlazados en el navbar y servidos nativamente en `/favicon.ico` y `/favicon.svg`. |
| 2026-10-21 | Blindaje de seguridad y protección contra ejecución de scripts (RCE/XSS/MIME) | Se auditaron riesgos de subida de scripts (.php, .phtml, .sh, .html, .svg). Se neutralizó la detección de MIME impidiendo que scripts se sirvan como ejecutables o HTML activo (Stored XSS). Se implementó Sandbox CSP, nosniff, DENY de frames en /raw/, permisos estrictos 0640 sin +x en disco, .htaccess preventivo en uploads/, flag Secure en cookies HTTPS, límite de 5 MB en share-text y sanitización reforzada contra path traversal multiplataforma. |
--- ---
@@ -27,7 +33,9 @@ Versión funcional completa y validada:
- Visor universal adaptativo con vista previa multimedia, lector de PDF y código con botón de copia. - Visor universal adaptativo con vista previa multimedia, lector de PDF y código con botón de copia.
- Purga automática cada 10 minutos para archivos guest > 24h (test automatizado superado en `main_test.go`). - Purga automática cada 10 minutos para archivos guest > 24h (test automatizado superado en `main_test.go`).
- Cuentas registradas con almacenamiento permanente y panel `/mis-archivos`. - Cuentas registradas con almacenamiento permanente y panel `/mis-archivos`.
- Documentación e integración de infraestructura sincronizada con el MCP y global `infraestructura.md`. - Registrado oficialmente en el MCP de Infraestructura (ID 34) y sincronizado con espejo local `.agente/infraestructura.md`.
- Desplegado y ejecutándose activamente en producción (CT 132 puerto 2008) supervisado por SIAX Monitor.
- Enrutamiento público operativo al 100% en `https://drop.sigmac.app` con SSL.
--- ---
@@ -40,6 +48,14 @@ Versión funcional completa y validada:
- [x] Implementar auth con WebControl (`api.siax-system.net`) y Google OAuth2 - [x] Implementar auth con WebControl (`api.siax-system.net`) y Google OAuth2
- [x] Implementar panel "Mis Archivos" para usuarios autenticados - [x] Implementar panel "Mis Archivos" para usuarios autenticados
- [x] Sincronizar sección de infraestructura en global e internal para MCP - [x] Sincronizar sección de infraestructura en global e internal para MCP
- [x] Crear scripts de despliegue estándar (`desplegar.sh`, `init.sh`, `servers.conf.example`)
- [x] Integrar servicio systemd para SIAX Monitor (`siax-app-DROP_SIGMAC_APP.service`)
- [x] Soporte para proxy reverso dinámico Apache (`X-Forwarded-Proto`, `Host`) en puerto 2008
- [x] Registrar proyecto en MCP de Infraestructura (ID 34) y crear `id_agente.md` oficial
- [x] Desplegar en producción en `server-webapps` (CT 132, :2008) y registrar en SIAX Monitor (:8080)
- [x] Crear icono SVG/PNG/ICO e integrarlo en la cabecera, navbar y servidor HTTP en producción
- [x] Auditar y blindar seguridad contra RCE, Stored XSS, MIME sniffing, Path Traversal y DoS en subidas y raw
--- ---
+47
View File
@@ -0,0 +1,47 @@
# reglas.md — Reglas operativas y técnicas de app_compartir (drop.sigmac.app)
> Normas inviolables que todo agente o desarrollador debe respetar al interactuar con este proyecto.
---
## 1. Identidad del Agente
- Mantener siempre el archivo [`id_agente.md`](../id_agente.md) en la raíz del repositorio según la norma del ecosistema.
- **No inventar nombres ni identificadores de agente**: El nombre oficial y el ID numérico son potestad exclusiva de la confirmación emitida por `sigma-robot` y autorizada por `pablinux`.
- Al inicio de cada sesión ("carga proyecto"), leer `id_agente.md` y `agents.md` para conocer el estado y credenciales.
- Nunca commitear tokens, contraseñas ni códigos secretos (`SIGMA_AGENTE_SOLICITUD_ID`, `SIGMA_AGENTE_CODIGO`, `SIGMA_AGENTE_TOKEN`).
---
## 2. Infraestructura y MCP
- **Prohibido asumir o inventar IPs, puertos o servidores**:
- Servidor de producción asignado: `server-webapps` CT 132 (`192.168.10.160`).
- Puerto de producción interno: `2008` (puerto local de desarrollo: `8085`).
- Dominio público: `https://drop.sigmac.app` (Reverse Proxy Apache con SSL/TLS Let's Encrypt).
- Servicio systemd: `siax-app-DROP_SIGMAC_APP.service` (gestionado y supervisado por SIAX Monitor en el puerto `8080`).
- Base de datos: SQLite en modo WAL (`data/compartir.db`) sin dependencias de MySQL ni MongoDB.
- Registro central MCP: Ficha técnica registrada en MariaDB con **ID 34** (categoría `application`, tipo `web`).
- El archivo [`.agente/infraestructura.md`](infraestructura.md) es un espejo local de solo lectura del documento maestro `/home/pablinux/Projects/infraestructura.md`. Nunca modificarlo de forma independiente sin sincronizar con el maestro.
---
## 3. Reglas de Negocio y Ciclo de Vida de Archivos
- **Política de Retención Estricta**:
- **Invitados (Guest)**: Cero fricción (sin login requerido). Todo archivo, nota o código subido como invitado tiene una vida útil máxima e inmutable de **24 horas**. El worker en segundo plano (`cleaner.go`) purga periódicamente tanto el archivo físico en disco como su fila en SQLite.
- **Usuarios Registrados (WebControl / Google OAuth)**: Disponen de almacenamiento **permanente**. Sus archivos nunca expiran ni son tocados por el limpiador automático. Tienen gestión completa desde `/mis-archivos`.
- **Generación de Código QR**:
- Se genera de forma nativa en backend Go vía `github.com/skip2/go-qrcode` en endpoint `/qr/{id}` como imagen PNG. Cero dependencias pesadas de librerías JS cliente para la generación del código QR.
- **Visor Universal Embebido**:
- El visor `/v/{id}` debe renderizar vista previa directa según el MIME type (imágenes con modal zoom, reproductor HTML5 de video/audio, visualizador embebido de PDF, y código formateado con botón de copia con un clic).
---
## 4. Comandos de Contexto del Ecosistema
- **"carga proyecto"**: Leer `agents.md`, `id_agente.md` y la carpeta `.agente/` para absorber el contexto, reglas, objetivos y memoria técnica antes de ejecutar modificaciones.
- **"actualizar proyecto"**: Ejecutar tests automatizados (`go test -v ./...`), realizar commit estructurado de los cambios pendientes, actualizar `agents.md`, `README.md` y `.agente/proyecto_estructura.md`.
---
## 5. Seguridad y Dependencias
- Compilar binarios de producción sin CGO (`CGO_ENABLED=0 GOOS=linux GOARCH=amd64`), utilizando la implementación pura en Go de SQLite (`modernc.org/sqlite`).
- Mantener las rutas de almacenamiento dentro de `DATA_DIR` y utilizar nombres generados criptográficamente (slugs no predecibles) para prevenir ataques de Path Traversal.
- Toda sesión web debe utilizar cookies seguras HTTP-only protegidas por `SESSION_SECRET`.
+63
View File
@@ -0,0 +1,63 @@
# tareas.md — Control de tareas de app_compartir (drop.sigmac.app)
> Registro ágil de tareas completadas, en progreso y backlog priorizado.
---
## ✅ Tareas Completadas
- [x] **Base de Datos y Esquema:** SQLite DAL (`modernc.org/sqlite`) con tablas `shares`, `users`, `sessions` en modo WAL.
- [x] **Subida de Archivos y Texto:** Endpoints `/api/upload` (multipart hasta 500 MB) y `/api/share-text` (notas rápidas y código).
- [x] **Visor Universal Adaptativo (`/v/{id}`):** Vista previa nativa para imágenes con zoom, video HTML5, audio HTML5, lector de PDF embebido y visualizador de código con botón de copia.
- [x] **Generador de QR Nativo:** Endpoint `/qr/{id}` con salida PNG (256x256) generado en Go nativo vía `github.com/skip2/go-qrcode`.
- [x] **Worker de Purga Automática 24h:** Goroutine en segundo plano (`cleaner.go`) que elimina archivos físicos y filas de BD vencidas de usuarios Guest.
- [x] **Autenticación Dual:** Login corporativo con Telcotronics WebControl (`api.siax-system.net`) y Google OAuth2.
- [x] **Panel "Mis Archivos":** Interfaz `/mis-archivos` para usuarios autenticados con almacenamiento permanente, estadísticas y borrado manual.
- [x] **Scripts de Despliegue:** `desplegar.sh` (compilación Linux amd64, transferencia scp/rsync) e `init.sh` (ejecutor en servidor).
- [x] **Integración con SIAX Monitor:** Servicio systemd `siax-app-DROP_SIGMAC_APP.service` para supervisión en puerto 2008 / 8080.
- [x] **Soporte de Reverse Proxy:** Manejo dinámico de encabezados Apache (`X-Forwarded-Proto`, `Host`, `X-Forwarded-For`).
- [x] **Pruebas Automatizadas:** Suite de tests unitarios y de integración en `main_test.go` verificando la retención 24h vs permanencia.
- [x] **Registro en MCP de Infraestructura:** Registrado oficialmente con **ID 34** en MariaDB (`http://192.168.10.160:3007/api/services/34`).
- [x] **Espejo de Infraestructura:** Sincronizado `.agente/infraestructura.md` con `/home/pablinux/Projects/infraestructura.md`.
- [x] **Identidad del Agente:** Creación de `id_agente.md` en la raíz del repositorio.
- [x] **Centro de Comunicaciones sigma-robot:** Autorizado formalmente por Pablinux como **Agente ID 86** (`Agente drop.sigmac.app`). Token definitivo resguardado en `.env` (modo 600).
- [x] **Despliegue a Producción (CT 132 server-webapps):** Desplegado y ejecutándose activamente como `siax-app-DROP_SIGMAC_APP.service` supervisado por SIAX Monitor (`:8080`), escuchando en puerto interno `2008` (dejando el 2006 reservado para `audio_control`). Subida atómica y reinicio automático operativo.
- [x] **Proxy Reverso Apache (SSL port 443 en CT 150):** Configurado por Pablinux y verificado operando al 100% en `https://drop.sigmac.app` (redirección 301 de HTTP a HTTPS, terminación SSL y proxy a `:2008`). Detección inteligente de HTTPS en enlaces generados y códigos QR.
- [x] **Identidad Visual e Iconos del Proyecto:** Creación de conjunto completo de iconos SVG vectoriales y ráster (SVG, ICO multi-resolución, PNG 64/192/512 px) con temática visual de transferencia (verde esmeralda / cian sobre grafito). Integrados en `web/templates/base.html` (meta tags, favicon, icono de marca en navbar) y expuestos vía `/favicon.ico`, `/favicon.svg` y `/static/*`. Desplegado en producción.
- [x] **Auditoría y Blindaje de Seguridad en Subidas (RCE / Stored XSS / MIME Sniffing):**
- Neutralización de scripts `.php`, `.phtml`, `.phar`, `.sh`, `.cgi` y archivos `.html` para que nunca se sirvan como ejecutables o código HTML activo.
- Implementación de cabeceras de Sandbox (`Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; sandbox`, `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`) en `/raw/{id}`.
- Middleware global de cabeceras de seguridad (`nosniff`, `SAMEORIGIN`, `strict-origin-when-cross-origin`, `Permissions-Policy`).
- Protección en disco con permisos `0640` (sin bit `+x`) y archivo preventivo `.htaccess` en `uploads/` (`Require all denied` para scripts).
- Sanitización anti-path traversal multiplataforma (eliminando `\` y secuencias `..`).
- Protección de cookies de sesión con flag `Secure: true` bajo HTTPS.
- Límite de 5 MB en endpoint `/api/share-text` contra DoS por memoria.
- Suite de pruebas de seguridad automatizada en `main_test.go` (`TestSecurityProtections`).
---
## 🚀 En Progreso / Inmediatas
- [x] **Creación del Repositorio Git Remoto:**
- Configurado en `https://git.telcotronics.net/pablinux/app_compartir.git`.
- Rama `main` 100% sincronizada y verificada con `origin`.
---
## 📋 Backlog Priorizado
### Fase 2: Experiencia y Utilidades
- [ ] **Descarga Multi-archivo Comprimida (.zip):**
- Empaquetar múltiples archivos en un único archivo zip descargable al vuelo.
- [ ] **Transferencia Directa P2P (WebRTC):**
- Tráfico directo punto a punto navegador a navegador para archivos de gran volumen sin persistencia en disco del servidor.
- [ ] **Protección por PIN / Contraseña opcional:**
- Permitir a quien comparte proteger el visor con una clave de 4-6 dígitos.
- [ ] **Modo de un solo uso (Burn after reading):**
- Auto-destrucción inmediata del archivo tras la primera descarga o visualización.
### Fase 3: Integraciones del Ecosistema
- [ ] **Notificaciones a sigma-robot:**
- Enviar eventos al bot o a Pablinux cuando se descargue un archivo relevante.
- [ ] **Widget publicitario app_marketing:**
- Integrar widget ligero de `ads.sigmac.app` opcional en la pantalla de descarga de invitados.
+12 -3
View File
@@ -157,7 +157,16 @@ app_compartir/
--- ---
## 🏢 Ecosistema Telcotronics ## 🏢 Ecosistema Telcotronics e Infraestructura
Este proyecto forma parte del ecosistema Telcotronics y se encuentra registrado en la infraestructura compartida del MCP (`mcp.telcotronics.net` / `infraestructura.md`). Este proyecto forma parte oficial del **Ecosistema Telcotronics** y se encuentra integrado con las siguientes especificaciones:
Para más detalles técnicos y reglas del agente, consultar [`agents.md`](agents.md).
| Entorno / Servicio | Detalle de Conexión |
|---|---|
| **Registro Central MCP** | Registrado en MariaDB como **Servicio ID 34** (Categoría: `application`) |
| **Centro de Agentes (sigma-robot)** | **Agente ID 86** (`Agente drop.sigmac.app`) activo y autorizado vía API REST |
| **Servidor de Producción** | `server-webapps` CT 132 (`192.168.10.160`), puerto interno `2008` |
| **Dominio y Proxy Apache** | `https://drop.sigmac.app` con terminación SSL/TLS Let's Encrypt (✅ Operativo) |
| **Supervisión de Procesos** | Servicio `siax-app-DROP_SIGMAC_APP.service` en [SIAX Monitor](http://192.168.10.160:8080) |
| **Identidad y Normas** | Consultar [`id_agente.md`](id_agente.md), [`agents.md`](agents.md) y [`.agente/reglas.md`](.agente/reglas.md) |
| **Espejo de Infraestructura** | Sincronizado en [`.agente/infraestructura.md`](.agente/infraestructura.md) desde `/home/pablinux/Projects/infraestructura.md` |
+10 -3
View File
@@ -74,10 +74,11 @@ Goroutine periódica (ticker) que consulta items donde `is_guest = true AND expi
| Parámetro | Valor | | Parámetro | Valor |
|---|---| |---|---|
| Dominio público | `drop.sigmac.app` | | Dominio público | `drop.sigmac.app` |
| Puerto interno | `2006` (producción) / `8085` (local) | | Puerto interno | `2008` (producción) / `8085` (local) |
| Servicio systemd | `app-compartir.service` | | Servicio systemd | `siax-app-DROP_SIGMAC_APP.service` (gestionado por SIAX Monitor) |
| BD principal | SQLite local (`data/compartir.db`) | | BD principal | SQLite local (`data/compartir.db`) |
| MCP ecosistema | `mcp.telcotronics.net` 🔧 en mantenimiento | | MCP ID | `34` (registrado en `http://192.168.10.160:3007/api/services` / SSE `:3006`) |
| Centro de agentes (sigma-robot) | Activo como **Agente ID 86** (autorizado por pablinux vía API REST) |
--- ---
@@ -92,6 +93,9 @@ Goroutine periódica (ticker) que consulta items donde `is_guest = true AND expi
| `GOOGLE_CLIENT_ID` | Client ID de Google OAuth | (opcional) | | `GOOGLE_CLIENT_ID` | Client ID de Google OAuth | (opcional) |
| `GOOGLE_CLIENT_SECRET` | Client Secret de Google OAuth | (opcional) | | `GOOGLE_CLIENT_SECRET` | Client Secret de Google OAuth | (opcional) |
| `WEBCONTROL_API_URL` | URL de autenticación de WebControl | `https://api.siax-system.net/api/auth/login` | | `WEBCONTROL_API_URL` | URL de autenticación de WebControl | `https://api.siax-system.net/api/auth/login` |
| `SIGMA_AGENTE_SOLICITUD_ID` | ID de solicitud en sigma-robot (nunca commitear) | (local `.env`) |
| `SIGMA_AGENTE_CODIGO` | Código secreto en sigma-robot (nunca commitear) | (local `.env`) |
| `SIGMA_AGENTE_TOKEN` | Token bearer permanente tras autorización (nunca commitear) | (local `.env`) |
--- ---
@@ -113,6 +117,7 @@ go run main.go
app_compartir/ app_compartir/
├── README.md ├── README.md
├── agents.md # ← LEER PRIMERO ├── agents.md # ← LEER PRIMERO
├── id_agente.md # Identidad del agente en el ecosistema
├── go.mod ├── go.mod
├── main.go ├── main.go
└── .agente/ └── .agente/
@@ -121,6 +126,8 @@ app_compartir/
├── proyecto_memoria.md # Decisiones técnicas e historial ├── proyecto_memoria.md # Decisiones técnicas e historial
├── proyecto_errores.md # Registro de errores ├── proyecto_errores.md # Registro de errores
├── objetivos.md # Qué debe cumplirse (sin fecha) ├── objetivos.md # Qué debe cumplirse (sin fecha)
├── reglas.md # Normas operativas y técnicas inviolables
├── tareas.md # Control ágil de tareas y backlog
└── ideas.md # Posibilidades sin compromiso └── ideas.md # Posibilidades sin compromiso
``` ```
+18 -7
View File
@@ -53,7 +53,7 @@ compilar() {
preparar_remoto() { preparar_remoto() {
echo "" echo ""
echo "📂 Preparando estructura de directorios en $SERVIDOR:$REMOTE_DIR..." echo "📂 Preparando estructura de directorios en $SERVIDOR:$REMOTE_DIR..."
remote "mkdir -p '$REMOTE_DIR/web/templates' '$REMOTE_DIR/data/uploads'" remote "mkdir -p '$REMOTE_DIR/web/templates' '$REMOTE_DIR/web/static' '$REMOTE_DIR/data/uploads'"
echo "✅ Directorios listos" echo "✅ Directorios listos"
} }
@@ -63,10 +63,13 @@ subir() {
preparar_remoto preparar_remoto
echo "" echo ""
echo "🚀 Subiendo binario, plantillas y scripts al servidor..." echo "🚀 Subiendo binario (atómico), plantillas y scripts al servidor..."
copy "$SCRIPT_DIR/app_compartir" "$SCRIPT_DIR/init.sh" "$SCRIPT_DIR/.env.example" "$SERVIDOR:$REMOTE_DIR/" copy "$SCRIPT_DIR/app_compartir" "$SERVIDOR:$REMOTE_DIR/app_compartir.tmp"
remote "mv -f '$REMOTE_DIR/app_compartir.tmp' '$REMOTE_DIR/app_compartir' && chmod 0755 '$REMOTE_DIR/app_compartir'"
copy "$SCRIPT_DIR/init.sh" "$SCRIPT_DIR/.env.example" "$SCRIPT_DIR/siax-app-DROP_SIGMAC_APP.service" "$SERVIDOR:$REMOTE_DIR/"
copy "$SCRIPT_DIR/web/templates/"*.html "$SERVIDOR:$REMOTE_DIR/web/templates/" copy "$SCRIPT_DIR/web/templates/"*.html "$SERVIDOR:$REMOTE_DIR/web/templates/"
remote "chmod 0755 '$REMOTE_DIR/app_compartir' '$REMOTE_DIR/init.sh'" copy "$SCRIPT_DIR/web/static/"* "$SERVIDOR:$REMOTE_DIR/web/static/"
remote "chmod 0755 '$REMOTE_DIR/init.sh'"
echo "✅ Archivos sincronizados en $REMOTE_DIR" echo "✅ Archivos sincronizados en $REMOTE_DIR"
} }
@@ -85,7 +88,7 @@ todo() {
echo "==================================================" echo "=================================================="
echo "🎉 ¡Despliegue completado con éxito!" echo "🎉 ¡Despliegue completado con éxito!"
echo "🌐 Dominio público: https://drop.sigmac.app" echo "🌐 Dominio público: https://drop.sigmac.app"
echo "🎯 Destino interno: http://$HOST:2006" echo "🎯 Destino interno: http://$HOST:2008"
echo "==================================================" echo "=================================================="
} }
@@ -94,12 +97,20 @@ estado() {
echo "" echo ""
echo "📊 Estado del servidor en $SERVIDOR:" echo "📊 Estado del servidor en $SERVIDOR:"
remote " remote "
if tmux has-session -t drop-sigmac-app 2>/dev/null; then if curl -sI http://localhost:8080/api/apps 2>/dev/null | grep -q '200 OK'; then
echo '==> Estado en SIAX Monitor (:8080):'
curl -s http://localhost:8080/api/apps | grep -o '{\"name\":\"DROP_SIGMAC_APP\"[^}]*}' || true
echo ''
fi
if systemctl is-active --quiet siax-app-DROP_SIGMAC_APP.service 2>/dev/null; then
echo '==> Servicio systemd siax-app-DROP_SIGMAC_APP (SIAX Monitor) activo:'
journalctl -u siax-app-DROP_SIGMAC_APP.service -n 12 --no-pager -q
elif tmux has-session -t drop-sigmac-app 2>/dev/null; then
echo '==> Sesión tmux drop-sigmac-app activa:' echo '==> Sesión tmux drop-sigmac-app activa:'
tmux capture-pane -pt drop-sigmac-app | tail -n 25 tmux capture-pane -pt drop-sigmac-app | tail -n 25
elif systemctl is-active --quiet drop-sigmac-app.service 2>/dev/null; then elif systemctl is-active --quiet drop-sigmac-app.service 2>/dev/null; then
echo '==> Servicio systemd drop-sigmac-app activo:' echo '==> Servicio systemd drop-sigmac-app activo:'
systemctl status drop-sigmac-app.service --no-pager journalctl -u drop-sigmac-app.service -n 12 --no-pager -q
else else
echo '⚠️ No se detectó proceso activo en tmux ni systemd.' echo '⚠️ No se detectó proceso activo en tmux ni systemd.'
fi fi
+9
View File
@@ -0,0 +1,9 @@
# Identidad del agente
- Proyecto: app_compartir
- Nombre asignado en sigma-robot: Agente drop.sigmac.app
- ID de agente en sigma-robot: 86
- Estado: activo
- Autorizado por: pablinux
- Canal: API REST (`https://sigma-bot.telcotronics.com/ecosistema/v1/agentes`)
- Credenciales: Guardadas de forma segura en `.env` local (`SIGMA_AGENTE_TOKEN`); nunca en Git ni en mensajes.
+27 -7
View File
@@ -13,8 +13,8 @@ if [[ ! -f "$SCRIPT_DIR/.env" ]]; then
if [[ -f "$SCRIPT_DIR/.env.example" ]]; then if [[ -f "$SCRIPT_DIR/.env.example" ]]; then
echo "==> Creando .env inicial desde .env.example..." echo "==> Creando .env inicial desde .env.example..."
cp "$SCRIPT_DIR/.env.example" "$SCRIPT_DIR/.env" cp "$SCRIPT_DIR/.env.example" "$SCRIPT_DIR/.env"
# Configurar puerto de producción 2006 y URL por defecto # Configurar puerto de producción 2008 y URL por defecto
sed -i 's/^PORT=.*/PORT=2006/' "$SCRIPT_DIR/.env" sed -i 's/^PORT=.*/PORT=2008/' "$SCRIPT_DIR/.env"
sed -i 's|^BASE_URL=.*|BASE_URL=https://drop.sigmac.app|' "$SCRIPT_DIR/.env" sed -i 's|^BASE_URL=.*|BASE_URL=https://drop.sigmac.app|' "$SCRIPT_DIR/.env"
else else
echo "⚠️ Advertencia: No se encontró .env ni .env.example." echo "⚠️ Advertencia: No se encontró .env ni .env.example."
@@ -27,11 +27,31 @@ mkdir -p "$SCRIPT_DIR/data/uploads"
# 3. Permisos de ejecución al binario # 3. Permisos de ejecución al binario
chmod +x "$SCRIPT_DIR/app_compartir" chmod +x "$SCRIPT_DIR/app_compartir"
# 4. Modo de arranque: Si existe servicio systemd, usarlo; de lo contrario, sesión tmux # 4. Modo de arranque: SIAX Monitor API, systemd o tmux
if systemctl is-active --quiet drop-sigmac-app.service 2>/dev/null || [ -f /etc/systemd/system/drop-sigmac-app.service ]; then if curl -sI http://localhost:8080/api/apps 2>/dev/null | grep -q "200 OK"; then
echo "==> Reiniciando servicio systemd 'drop-sigmac-app.service'..." echo "==> Reiniciando DROP_SIGMAC_APP vía API de SIAX Monitor (:8080)..."
sudo systemctl restart drop-sigmac-app.service RESP=$(curl -s -X POST http://localhost:8080/api/apps/DROP_SIGMAC_APP/restart)
sudo systemctl status drop-sigmac-app.service --no-pager echo " Respuesta: $RESP"
if echo "$RESP" | grep -q '"success":true'; then
echo "✅ Servicio reiniciado exitosamente por SIAX Monitor."
exit 0
fi
fi
SERVICE_NAME=""
if systemctl is-active --quiet siax-app-DROP_SIGMAC_APP.service 2>/dev/null || [ -f /etc/systemd/system/siax-app-DROP_SIGMAC_APP.service ]; then
SERVICE_NAME="siax-app-DROP_SIGMAC_APP.service"
elif systemctl is-active --quiet drop-sigmac-app.service 2>/dev/null || [ -f /etc/systemd/system/drop-sigmac-app.service ]; then
SERVICE_NAME="drop-sigmac-app.service"
fi
if [[ -n "$SERVICE_NAME" ]]; then
echo "==> Reiniciando servicio systemd '$SERVICE_NAME'..."
if sudo -n true 2>/dev/null; then
sudo systemctl restart "$SERVICE_NAME"
else
systemctl restart "$SERVICE_NAME" 2>/dev/null || true
fi
exit 0 exit 0
fi fi
+19
View File
@@ -59,6 +59,21 @@ func (a *AuthService) GenerateToken(length int) string {
return hex.EncodeToString(bytes) return hex.EncodeToString(bytes)
} }
func (a *AuthService) isSecureRequest(r *http.Request) bool {
if r.TLS != nil {
return true
}
if strings.EqualFold(r.Header.Get("X-Forwarded-Proto"), "https") ||
strings.EqualFold(r.Header.Get("X-Forwarded-Ssl"), "on") ||
r.Header.Get("X-Forwarded-Port") == "443" {
return true
}
if strings.HasPrefix(a.cfg.BaseURL, "https://") {
return true
}
return false
}
func (a *AuthService) GetOrCreateSession(w http.ResponseWriter, r *http.Request) *models.Session { func (a *AuthService) GetOrCreateSession(w http.ResponseWriter, r *http.Request) *models.Session {
cookie, err := r.Cookie(CookieSessionName) cookie, err := r.Cookie(CookieSessionName)
if err == nil && cookie.Value != "" { if err == nil && cookie.Value != "" {
@@ -93,6 +108,7 @@ func (a *AuthService) GetOrCreateSession(w http.ResponseWriter, r *http.Request)
Path: "/", Path: "/",
Expires: expiresAt, Expires: expiresAt,
HttpOnly: true, HttpOnly: true,
Secure: a.isSecureRequest(r),
SameSite: http.SameSiteLaxMode, SameSite: http.SameSiteLaxMode,
}) })
@@ -124,6 +140,7 @@ func (a *AuthService) AttachUserToSession(w http.ResponseWriter, r *http.Request
Path: "/", Path: "/",
Expires: expiresAt, Expires: expiresAt,
HttpOnly: true, HttpOnly: true,
Secure: a.isSecureRequest(r),
SameSite: http.SameSiteLaxMode, SameSite: http.SameSiteLaxMode,
}) })
@@ -142,6 +159,8 @@ func (a *AuthService) Logout(w http.ResponseWriter, r *http.Request) {
Expires: time.Unix(0, 0), Expires: time.Unix(0, 0),
MaxAge: -1, MaxAge: -1,
HttpOnly: true, HttpOnly: true,
Secure: a.isSecureRequest(r),
SameSite: http.SameSiteLaxMode,
}) })
} }
+78 -7
View File
@@ -72,7 +72,10 @@ type PageData struct {
func (h *Handlers) getBaseURL(r *http.Request) string { func (h *Handlers) getBaseURL(r *http.Request) string {
proto := "http" proto := "http"
if r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https" { if r.TLS != nil ||
strings.EqualFold(r.Header.Get("X-Forwarded-Proto"), "https") ||
strings.EqualFold(r.Header.Get("X-Forwarded-Ssl"), "on") ||
r.Header.Get("X-Forwarded-Port") == "443" {
proto = "https" proto = "https"
} }
host := r.Host host := r.Host
@@ -80,6 +83,9 @@ func (h *Handlers) getBaseURL(r *http.Request) string {
host = r.Header.Get("X-Forwarded-Host") host = r.Header.Get("X-Forwarded-Host")
} }
if host != "" { if host != "" {
if strings.HasPrefix(h.cfg.BaseURL, "https://") && strings.Contains(h.cfg.BaseURL, host) {
proto = "https"
}
return fmt.Sprintf("%s://%s", proto, host) return fmt.Sprintf("%s://%s", proto, host)
} }
return h.cfg.BaseURL return h.cfg.BaseURL
@@ -205,12 +211,15 @@ func (h *Handlers) ShareText(w http.ResponseWriter, r *http.Request) {
return return
} }
// Límite de 5 MB para evitar DoS por memoria
r.Body = http.MaxBytesReader(w, r.Body, 5<<20)
var req struct { var req struct {
Title string `json:"title"` Title string `json:"title"`
Text string `json:"text"` Text string `json:"text"`
} }
if err := json.NewDecoder(r.Body).Decode(&req); err != nil || strings.TrimSpace(req.Text) == "" { if err := json.NewDecoder(r.Body).Decode(&req); err != nil || strings.TrimSpace(req.Text) == "" {
http.Error(w, "Contenido de texto requerido", http.StatusBadRequest) http.Error(w, "Contenido de texto requerido o tamaño excesivo (máx 5 MB)", http.StatusBadRequest)
return return
} }
@@ -316,6 +325,17 @@ func (h *Handlers) View(w http.ResponseWriter, r *http.Request) {
_ = h.db.IncrementViews(id) _ = h.db.IncrementViews(id)
share.ViewsCount++ share.ViewsCount++
// Si es un archivo de texto/código y no tiene TextContent, leer hasta 512 KB para vista previa segura
isText := strings.HasPrefix(share.MimeType, "text/") || share.Type == "text"
if isText && share.TextContent == "" && share.StoredPath != "" {
fullPath := filepath.Join(h.cfg.UploadDir, share.StoredPath)
if fi, err := os.Stat(fullPath); err == nil && fi.Size() <= 512*1024 {
if content, err := os.ReadFile(fullPath); err == nil {
share.TextContent = string(content)
}
}
}
session := h.auth.GetOrCreateSession(w, r) session := h.auth.GetOrCreateSession(w, r)
data := PageData{ data := PageData{
Session: session, Session: session,
@@ -325,7 +345,7 @@ func (h *Handlers) View(w http.ResponseWriter, r *http.Request) {
IsVideo: strings.HasPrefix(share.MimeType, "video/"), IsVideo: strings.HasPrefix(share.MimeType, "video/"),
IsAudio: strings.HasPrefix(share.MimeType, "audio/"), IsAudio: strings.HasPrefix(share.MimeType, "audio/"),
IsPDF: share.MimeType == "application/pdf", IsPDF: share.MimeType == "application/pdf",
IsText: strings.HasPrefix(share.MimeType, "text/") || share.Type == "text", IsText: isText,
} }
tmpl := h.templates["viewer.html"] tmpl := h.templates["viewer.html"]
@@ -345,6 +365,35 @@ func (h *Handlers) renderExpired(w http.ResponseWriter, r *http.Request) {
_ = tmpl.ExecuteTemplate(w, "base.html", data) _ = tmpl.ExecuteTemplate(w, "base.html", data)
} }
func isSafeInlineMime(mimeType string) bool {
switch mimeType {
case "image/png", "image/jpeg", "image/gif", "image/webp", "image/bmp", "image/x-icon":
return true
case "audio/mpeg", "audio/wav", "audio/ogg", "audio/webm", "audio/aac", "audio/flac":
return true
case "video/mp4", "video/webm", "video/ogg":
return true
case "application/pdf":
return true
case "text/plain", "text/plain; charset=utf-8":
return true
case "image/svg+xml":
return true
default:
return false
}
}
func sanitizeHeaderFilename(name string) string {
cleaned := strings.ReplaceAll(name, "\r", "")
cleaned = strings.ReplaceAll(cleaned, "\n", "")
cleaned = strings.ReplaceAll(cleaned, "\"", "_")
if strings.TrimSpace(cleaned) == "" {
cleaned = "archivo.bin"
}
return cleaned
}
func (h *Handlers) Download(w http.ResponseWriter, r *http.Request) { func (h *Handlers) Download(w http.ResponseWriter, r *http.Request) {
id := strings.TrimPrefix(r.URL.Path, "/d/") id := strings.TrimPrefix(r.URL.Path, "/d/")
if id == "" { if id == "" {
@@ -365,9 +414,12 @@ func (h *Handlers) Download(w http.ResponseWriter, r *http.Request) {
_ = h.db.IncrementDownloads(id) _ = h.db.IncrementDownloads(id)
w.Header().Set("X-Content-Type-Options", "nosniff")
safeTitle := sanitizeHeaderFilename(share.Title)
if share.Type == "text" { if share.Type == "text" {
w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", share.Title+".txt")) w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", safeTitle+".txt"))
_, _ = w.Write([]byte(share.TextContent)) _, _ = w.Write([]byte(share.TextContent))
return return
} }
@@ -378,7 +430,7 @@ func (h *Handlers) Download(w http.ResponseWriter, r *http.Request) {
return return
} }
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", share.Title)) w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", safeTitle))
http.ServeFile(w, r, fullPath) http.ServeFile(w, r, fullPath)
} }
@@ -400,8 +452,14 @@ func (h *Handlers) Raw(w http.ResponseWriter, r *http.Request) {
return return
} }
// Cabeceras de seguridad estrictas contra XSS y MIME-sniffing
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")
if share.Type == "text" { if share.Type == "text" {
w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("Content-Disposition", "inline")
_, _ = w.Write([]byte(share.TextContent)) _, _ = w.Write([]byte(share.TextContent))
return return
} }
@@ -412,8 +470,21 @@ func (h *Handlers) Raw(w http.ResponseWriter, r *http.Request) {
return return
} }
w.Header().Set("Content-Type", share.MimeType) // Neutralizar cualquier intento de servir HTML, PHP o scripts ejecutables inline
w.Header().Set("Content-Disposition", "inline") mimeType := share.MimeType
if strings.HasPrefix(mimeType, "text/html") || strings.Contains(mimeType, "php") || strings.Contains(mimeType, "javascript") {
mimeType = "text/plain; charset=utf-8"
}
w.Header().Set("Content-Type", mimeType)
if isSafeInlineMime(mimeType) {
w.Header().Set("Content-Disposition", "inline")
} else {
// Archivos ejecutables, binarios o desconocidos se fuerzan a descarga
safeTitle := sanitizeHeaderFilename(share.Title)
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", safeTitle))
}
http.ServeFile(w, r, fullPath) http.ServeFile(w, r, fullPath)
} }
+65 -30
View File
@@ -28,8 +28,19 @@ func GenerateSlug(length int) string {
} }
func SanitizeFilename(name string) string { func SanitizeFilename(name string) string {
base := filepath.Base(name) // Normalizar separadores de ruta (incluyendo Windows \)
normalized := strings.ReplaceAll(name, "\\", "/")
base := filepath.Base(normalized)
// Eliminar secuencias '..' para evitar cualquier ambigüedad
for strings.Contains(base, "..") {
base = strings.ReplaceAll(base, "..", ".")
}
sanitized := safeFilenameRegex.ReplaceAllString(base, "_") sanitized := safeFilenameRegex.ReplaceAllString(base, "_")
// Evitar archivos ocultos o nombres que empiecen por punto
sanitized = strings.TrimLeft(sanitized, "._-")
if len(sanitized) > 100 { if len(sanitized) > 100 {
ext := filepath.Ext(sanitized) ext := filepath.Ext(sanitized)
sanitized = sanitized[:100-len(ext)] + ext sanitized = sanitized[:100-len(ext)] + ext
@@ -42,25 +53,19 @@ func SanitizeFilename(name string) string {
func DetectMimeType(filename string, reader io.ReadSeeker) string { func DetectMimeType(filename string, reader io.ReadSeeker) string {
ext := strings.ToLower(filepath.Ext(filename)) ext := strings.ToLower(filepath.Ext(filename))
if m := mime.TypeByExtension(ext); m != "" {
return m
}
// Sniff first 512 bytes // 1. Extensiones peligrosas de scripts, código y plantillas: NUNCA ejecutables como text/html o php
if reader != nil {
buf := make([]byte, 512)
n, err := reader.Read(buf)
_, _ = reader.Seek(0, io.SeekStart)
if err == nil && n > 0 {
detected := http.DetectContentType(buf[:n])
if detected != "application/octet-stream" {
return detected
}
}
}
// Known fallback extensions
switch ext { switch ext {
case ".html", ".htm", ".shtml", ".xhtml", ".hta":
return "text/plain; charset=utf-8"
case ".php", ".phtml", ".php3", ".php4", ".php5", ".pht", ".phar", ".inc", ".cgi", ".pl", ".py", ".sh", ".bash", ".sql":
return "text/plain; charset=utf-8"
case ".js", ".mjs", ".ts", ".jsx", ".tsx":
return "text/plain; charset=utf-8"
case ".txt", ".log", ".env", ".ini", ".conf", ".yaml", ".yml", ".md", ".go", ".rs", ".java", ".c", ".cpp", ".h", ".css":
return "text/plain; charset=utf-8"
case ".json":
return "application/json"
case ".pdf": case ".pdf":
return "application/pdf" return "application/pdf"
case ".mp4": case ".mp4":
@@ -83,29 +88,59 @@ func DetectMimeType(filename string, reader io.ReadSeeker) string {
return "image/webp" return "image/webp"
case ".svg": case ".svg":
return "image/svg+xml" return "image/svg+xml"
case ".txt", ".log", ".env":
return "text/plain; charset=utf-8"
case ".json":
return "application/json"
case ".js":
return "application/javascript"
case ".go", ".py", ".rs", ".java", ".c", ".cpp", ".sh", ".sql", ".html", ".css", ".md":
return "text/plain; charset=utf-8"
default:
return "application/octet-stream"
} }
// 2. Consulta MIME del sistema para otras extensiones
if m := mime.TypeByExtension(ext); m != "" {
// Doble verificación: neutralizar si el sistema operativo clasifica como HTML o PHP
if strings.HasPrefix(m, "text/html") || strings.Contains(m, "php") || strings.Contains(m, "javascript") {
return "text/plain; charset=utf-8"
}
return m
}
// 3. Sniff de primeros 512 bytes
if reader != nil {
buf := make([]byte, 512)
n, err := reader.Read(buf)
_, _ = reader.Seek(0, io.SeekStart)
if err == nil && n > 0 {
detected := http.DetectContentType(buf[:n])
if detected != "application/octet-stream" {
if strings.HasPrefix(detected, "text/html") {
return "text/plain; charset=utf-8"
}
return detected
}
}
}
return "application/octet-stream"
} }
func SaveFile(uploadDir, slug, originalFilename string, src io.Reader) (string, int64, error) { func SaveFile(uploadDir, slug, originalFilename string, src io.Reader) (string, int64, error) {
if err := os.MkdirAll(uploadDir, 0755); err != nil { if err := os.MkdirAll(uploadDir, 0750); err != nil {
return "", 0, err return "", 0, err
} }
// Crear archivo preventivo .htaccess para bloquear cualquier motor de script si Apache apuntara aquí
htaccessPath := filepath.Join(uploadDir, ".htaccess")
if _, err := os.Stat(htaccessPath); os.IsNotExist(err) {
htaccessContent := `# Seguridad drop.sigmac.app: Desactivar ejecución de scripts
Options -ExecCGI -Indexes
<FilesMatch "\.(php|phtml|phar|pl|py|cgi|sh|bash)$">
Require all denied
</FilesMatch>
`
_ = os.WriteFile(htaccessPath, []byte(htaccessContent), 0644)
}
safeName := SanitizeFilename(originalFilename) safeName := SanitizeFilename(originalFilename)
storedFilename := slug + "_" + safeName storedFilename := slug + "_" + safeName
destPath := filepath.Join(uploadDir, storedFilename) destPath := filepath.Join(uploadDir, storedFilename)
dest, err := os.Create(destPath) // Crear con permisos 0640 (sin flag +x ejecutable)
dest, err := os.OpenFile(destPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil { if err != nil {
return "", 0, err return "", 0, err
} }
+23 -1
View File
@@ -56,6 +56,17 @@ func main() {
mux := http.NewServeMux() mux := http.NewServeMux()
// Archivos estáticos e iconos
fs := http.FileServer(http.Dir("web/static"))
mux.Handle("GET /static/", http.StripPrefix("/static/", fs))
mux.HandleFunc("GET /favicon.ico", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "web/static/favicon.ico")
})
mux.HandleFunc("GET /favicon.svg", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "image/svg+xml")
http.ServeFile(w, r, "web/static/favicon.svg")
})
// Rutas Web // Rutas Web
mux.HandleFunc("GET /", h.Index) mux.HandleFunc("GET /", h.Index)
mux.HandleFunc("GET /v/{id}", h.View) mux.HandleFunc("GET /v/{id}", h.View)
@@ -80,7 +91,7 @@ func main() {
server := &http.Server{ server := &http.Server{
Addr: ":" + cfg.Port, Addr: ":" + cfg.Port,
Handler: mux, Handler: securityHeadersMiddleware(mux),
ReadTimeout: 120 * time.Second, ReadTimeout: 120 * time.Second,
WriteTimeout: 120 * time.Second, WriteTimeout: 120 * time.Second,
IdleTimeout: 120 * time.Second, IdleTimeout: 120 * time.Second,
@@ -109,3 +120,14 @@ func main() {
} }
log.Println("👋 Servidor apagado correctamente.") log.Println("👋 Servidor apagado correctamente.")
} }
// securityHeadersMiddleware inyecta cabeceras de protección defensiva en todas las respuestas
func securityHeadersMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "SAMEORIGIN")
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
w.Header().Set("Permissions-Policy", "camera=(), microphone=(), geolocation=()")
next.ServeHTTP(w, r)
})
}
+77
View File
@@ -3,12 +3,14 @@ package main
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"time" "time"
"app_compartir/internal/cleaner" "app_compartir/internal/cleaner"
"app_compartir/internal/db" "app_compartir/internal/db"
"app_compartir/internal/models" "app_compartir/internal/models"
"app_compartir/internal/storage"
) )
func TestGuestExpirationAndRegisteredPermanence(t *testing.T) { func TestGuestExpirationAndRegisteredPermanence(t *testing.T) {
@@ -132,3 +134,78 @@ func TestGuestExpirationAndRegisteredPermanence(t *testing.T) {
t.Log("✅ Test completado con éxito: Solo los datos de invitado caducan en 24h; los de usuarios registrados son permanentes.") t.Log("✅ Test completado con éxito: Solo los datos de invitado caducan en 24h; los de usuarios registrados son permanentes.")
} }
func TestSecurityProtections(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "test_security_*")
if err != nil {
t.Fatalf("error creando tmpDir: %v", err)
}
defer os.RemoveAll(tmpDir)
uploadDir := filepath.Join(tmpDir, "uploads")
// 1. Probar Sanitización de Nombres (Path Traversal)
traversalTests := []struct {
input string
expected string
}{
{"../../../../etc/passwd", "etc_passwd"},
{"..\\..\\windows\\system32\\cmd.exe", "cmd.exe"},
{"test/../../shell.php", "shell.php"},
{"../../../.htaccess", "_.htaccess"},
}
for _, tc := range traversalTests {
sanitized := storage.SanitizeFilename(tc.input)
if strings.Contains(sanitized, "/") || strings.Contains(sanitized, "\\") || strings.Contains(sanitized, "..") {
t.Fatalf("Fallo en sanitización de path traversal para %s: resultado=%s", tc.input, sanitized)
}
}
// 2. Probar Detección de MIME Types Peligrosos (Neutralización de XSS y Scripts)
dangerousMimes := []struct {
filename string
forbidden string
expected string
}{
{"shell.php", "application/x-httpd-php", "text/plain; charset=utf-8"},
{"exploit.phtml", "text/html", "text/plain; charset=utf-8"},
{"malicious.html", "text/html", "text/plain; charset=utf-8"},
{"test.xhtml", "text/html", "text/plain; charset=utf-8"},
{"script.sh", "application/x-sh", "text/plain; charset=utf-8"},
}
for _, tc := range dangerousMimes {
m := storage.DetectMimeType(tc.filename, nil)
if m == tc.forbidden || strings.HasPrefix(m, "text/html") {
t.Fatalf("MIME peligroso no neutralizado para %s: obtenido %s (prohibido %s)", tc.filename, m, tc.forbidden)
}
if m != tc.expected {
t.Fatalf("MIME esperado %s para %s, obtenido %s", tc.expected, tc.filename, m)
}
}
// 3. Probar Guardado Seguro en Disco (Permisos no ejecutables y .htaccess preventivo)
sampleContent := strings.NewReader("<?php echo 'hacked'; ?>")
storedFile, _, err := storage.SaveFile(uploadDir, "secslug", "shell.php", sampleContent)
if err != nil {
t.Fatalf("error guardando archivo seguro: %v", err)
}
// Verificar permisos en disco (NO ejecutable)
destPath := filepath.Join(uploadDir, storedFile)
fi, err := os.Stat(destPath)
if err != nil {
t.Fatalf("error comprobando archivo guardado: %v", err)
}
mode := fi.Mode().Perm()
if mode&0111 != 0 {
t.Fatalf("El archivo guardado tiene permisos de ejecución: %o", mode)
}
// Verificar existencia de .htaccess preventivo
htaccessPath := filepath.Join(uploadDir, ".htaccess")
if _, err := os.Stat(htaccessPath); os.IsNotExist(err) {
t.Fatalf(".htaccess preventivo no fue creado en uploadDir")
}
t.Log("✅ Test completado con éxito: Protecciones de seguridad activas (sin path traversal, scripts neutralizados a texto plano y archivos no ejecutables).")
}
+16
View File
@@ -0,0 +1,16 @@
[Unit]
Description=SIAX App: drop.sigmac.app (Plataforma de Transferencia y Visor Rápido de Archivos)
After=network.target
[Service]
Type=simple
User=user_apps
WorkingDirectory=/home/user_apps/apps/drop_sigmac_app
ExecStart=/home/user_apps/apps/drop_sigmac_app/app_compartir
EnvironmentFile=/home/user_apps/apps/drop_sigmac_app/.env
Restart=always
RestartSec=5s
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

+75
View File
@@ -0,0 +1,75 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="100%" height="100%">
<defs>
<!-- Background Gradient -->
<linearGradient id="bgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#020617"/>
<stop offset="50%" stop-color="#0f172a"/>
<stop offset="100%" stop-color="#030712"/>
</linearGradient>
<!-- Border Glow Gradient -->
<linearGradient id="borderGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#10b981"/>
<stop offset="50%" stop-color="#06b6d4"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
<!-- Main Drop Gradient -->
<linearGradient id="dropGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#4ade80"/>
<stop offset="40%" stop-color="#22c55e"/>
<stop offset="80%" stop-color="#06b6d4"/>
<stop offset="100%" stop-color="#0284c7"/>
</linearGradient>
<!-- Inner Core Gradient -->
<linearGradient id="coreGrad" x1="0%" y1="100%" x2="0%" y2="0%">
<stop offset="0%" stop-color="#ffffff" stop-opacity="0.95"/>
<stop offset="100%" stop-color="#ecfdf5" stop-opacity="0.75"/>
</linearGradient>
<!-- Glow Filter -->
<filter id="neonGlow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="14" result="blur"/>
<feMerge>
<feMergeNode in="blur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<filter id="softShadow" x="-10%" y="-10%" width="120%" height="120%">
<feDropShadow dx="0" dy="8" stdDeviation="12" flood-color="#000000" flood-opacity="0.6"/>
</filter>
</defs>
<!-- Base Icon Container (Squircle) -->
<rect x="16" y="16" width="480" height="480" rx="112" fill="url(#bgGrad)" stroke="url(#borderGrad)" stroke-width="10" filter="url(#softShadow)"/>
<!-- Radial Glow Behind the Symbol -->
<circle cx="256" cy="256" r="140" fill="#22c55e" opacity="0.12" filter="url(#neonGlow)"/>
<!-- Wireless Transfer Signal Arches (Top Right) -->
<path d="M 320 120 A 70 70 0 0 1 380 180" fill="none" stroke="#38bdf8" stroke-width="12" stroke-linecap="round" opacity="0.75"/>
<path d="M 345 95 A 105 105 0 0 1 425 175" fill="none" stroke="#22c55e" stroke-width="12" stroke-linecap="round" opacity="0.45"/>
<!-- Main Teardrop / Fast Drop Silhouette -->
<!-- Smooth teardrop geometry combining drop + speed -->
<path d="M 256 90
C 256 90, 375 220, 375 320
A 119 119 0 0 1 137 320
C 137 220, 256 90, 256 90 Z"
fill="url(#dropGrad)"
filter="url(#neonGlow)"/>
<!-- Negative Space Inner Arrows (Bidirectional Fast Transfer) -->
<g fill="url(#coreGrad)">
<!-- Upward Transfer Arrow Head -->
<path d="M 256 160 L 298 215 L 274 215 L 274 275 L 238 275 L 238 215 L 214 215 Z"/>
<!-- Downward Transfer Chevron / Base Anchor -->
<path d="M 220 305 L 256 348 L 292 305 L 280 295 L 256 324 L 232 295 Z" opacity="0.9"/>
<!-- Energy Transfer Dot -->
<circle cx="256" cy="385" r="9" fill="#ffffff" opacity="0.95"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

+6 -3
View File
@@ -4,6 +4,11 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{block "title" .}}drop.sigmac.app — Pasa archivos y texto al instante{{end}}</title> <title>{{block "title" .}}drop.sigmac.app — Pasa archivos y texto al instante{{end}}</title>
<!-- Favicon & Touch Icons -->
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="alternate icon" type="image/x-icon" href="/favicon.ico">
<link rel="apple-touch-icon" href="/static/icon-192.png">
<!-- Tailwind CSS CDN --> <!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<script> <script>
@@ -44,9 +49,7 @@
<header class="border-b border-slate-800 bg-slate-900/80 backdrop-blur sticky top-0 z-50"> <header class="border-b border-slate-800 bg-slate-900/80 backdrop-blur sticky top-0 z-50">
<div class="max-w-6xl mx-auto px-4 h-16 flex items-center justify-between"> <div class="max-w-6xl mx-auto px-4 h-16 flex items-center justify-between">
<a href="/" class="flex items-center gap-2.5 font-bold text-lg tracking-tight hover:opacity-90 transition"> <a href="/" class="flex items-center gap-2.5 font-bold text-lg tracking-tight hover:opacity-90 transition">
<span class="w-9 h-9 rounded-xl bg-gradient-to-tr from-brand-600 to-emerald-400 flex items-center justify-center text-slate-950 font-black shadow-lg shadow-brand-500/20"> <img src="/favicon.svg" alt="Logo" class="w-9 h-9 rounded-xl shadow-lg shadow-brand-500/20 object-contain">
<i class="fa-solid fa-cloud-arrow-up text-base"></i>
</span>
<span class="text-white">drop<span class="text-brand-500">.sigmac.app</span></span> <span class="text-white">drop<span class="text-brand-500">.sigmac.app</span></span>
</a> </a>