Transferencia de archivos P2P cifrada de extremo a extremo, sin cuentas y sin límites de tamaño.
Los archivos viajan directamente entre dispositivos: el servidor actúa exclusivamente como señalizador para que ambos extremos se encuentren.
Tú Servidor Receptor
│ 1. Crear sala ──────► (devuelve "4271") ▲
│ + sorteas las palabras aquí mismo │
│ │
│ 2. Dictas 4271-lemon-radar-tiger-orbit ────────────┤ 3. Lo teclea, o abre el enlace
│◄── 4. Señalización (SDP/ICE o IPs locales) ────────►│
│ │
│ 5. TRANSFERENCIA P2P DIRECTA CIFRADA (E2EE) ──────►│
└─────────────────────────────────────────────────────┘
El código tiene dos mitades con papeles distintos: 4271 identifica la sala y es lo
único que viaja al servidor; las cuatro palabras son el secreto del que sale la clave
de cifrado y no salen nunca de tu equipo. Detalle completo en
Modelo de seguridad del código.
| Característica | 🌐 Drop Web | 💻 Drop CLI (drop) |
|---|---|---|
| Ideal para | Amigos, móviles, tablets, envíos rápidos | Archivos gigantes (ISOs, backups, vídeos) |
| Instalación | Cero. Solo abrir el navegador | Auto-instalable (1 clic) sin dependencias |
| Protocolo | WebRTC DataChannel | Sockets TCP directos + LAN UDP Broadcast |
| Velocidad | ~15 MB/s (límite SCTP del navegador) | 100–115 MB/s (satura Gigabit / Wi-Fi 6) |
| Compatibilidad | Con otro navegador y con el CLI | Con otro CLI y con el navegador (las cuatro combinaciones, ver Interoperabilidad) |
Descarga directa de los binarios autónomos (sin necesidad de tener Node.js instalado) desde la Release v0.10.1:
- Windows (x64):
drop-v0.10.1-windows-x64.exe - Linux (x64):
drop-v0.10.1-linux-x64.tar.gz - Linux (ARM64):
drop-v0.10.1-linux-arm64.tar.gz(Raspberry Pi, VPS Oracle ARM, AWS Graviton) - macOS (Apple Silicon):
drop-v0.10.1-macos-arm64.tar.gz(M1, M2, M3, M4) - macOS (Intel):
drop-v0.10.1-macos-x64.tar.gz
Cada release publica un SHA256SUMS con el hash de todos los binarios y un SHA256SUMS.minisig con su firma. Son dos comprobaciones distintas y conviene hacer las dos: el hash dice que el binario ha llegado entero, la firma dice que lo publicó quien tiene la clave del proyecto.
1. La firma (a partir de la v0.5.2), con minisign:
minisign -Vm SHA256SUMS -P RWQqNnfqvCrj+eavJ9njz2vCoHaC8YnLqjsvNBMndz3hBroQLpou7+KpEsa clave pública es la del proyecto; la privada solo la usa el workflow de release. Si minisign responde Signature and comment signature verified, el SHA256SUMS es auténtico.
2. El hash del binario que has bajado:
# Linux / macOS
sha256sum -c SHA256SUMS --ignore-missing
# Windows (PowerShell)
Get-FileHash drop-v0.10.1-windows-x64.exe -Algorithm SHA256drop update hace las dos por su cuenta antes de sustituir el ejecutable y aborta si algo no cuadra. Con una release anterior a la v0.5.2, que no lleva firma, avisa y exige --allow-unsigned para seguir: así, borrar la firma no basta para que se conforme con el hash.
# macOS y Linux, con Homebrew
brew install oloxx/tap/drop# Windows, con Scoop
scoop bucket add oloxx https://github.com/Oloxx/scoop-bucket
scoop install oloxx/dropSe actualizan con brew upgrade drop y scoop update drop, no con drop update: el binario es
del gestor, y desde la v0.10.0 drop lo detecta y te dice qué orden usar.
Ninguno de los dos provoca avisos de Gatekeeper o SmartScreen, y los dos manifiestos se generan
solo después de comprobar la firma minisign del SHA256SUMS de la release
(homebrew-tap, scoop-bucket).
Simplemente descarga drop-v0.10.1-windows-x64.exe y haz doble clic sobre él.
- Se abrirá una ventana que lo copiará automáticamente a tu carpeta de programas (
%LOCALAPPDATA%\Programs\drop\). - Añadirá de forma automática y permanente la ruta a tu variable de entorno
PATH. - Ya podrás abrir cualquier terminal (PowerShell, CMD o Windows Terminal) y usar directamente el comando
drop.
Descarga el archivo correspondiente, extráelo y ejecútalo con install:
tar -xzf drop-v0.10.1-linux-x64.tar.gz
./drop-v0.10.1-linux-x64 install(O muévelo manualmente a tu ruta del sistema: sudo mv drop-linux-x64 /usr/local/bin/drop && chmod +x /usr/local/bin/drop)
Los binarios van firmados con la clave del proyecto (ver Verificar la descarga), pero no con un certificado de Apple ni de Microsoft: esos cuestan dinero cada año y drop no los paga. Por eso, si descargas el binario con el navegador, el sistema avisa la primera vez. No es que esté dañado: es que no lo firmó alguien que el sistema conozca. Comprueba la firma y el hash como dice arriba y sigue así:
Lo más cómodo: descárgalo desde la terminal. Ni curl ni drop update marcan el archivo como
"bajado de Internet", así que no sale ningún aviso:
# macOS (Apple Silicon; cambia arm64 por x64 en un Mac Intel)
curl -LO https://github.com/Oloxx/drop/releases/download/v0.10.1/drop-v0.10.1-macos-arm64.tar.gz
tar -xzf drop-v0.10.1-macos-arm64.tar.gz && ./drop-v0.10.1-macos-arm64 install# Windows (curl.exe viene con Windows 10 y 11)
curl.exe -LO https://github.com/Oloxx/drop/releases/download/v0.10.1/drop-v0.10.1-windows-x64.exe
.\drop-v0.10.1-windows-x64.exeSi ya lo bajaste con el navegador:
- macOS dice que no se puede verificar el desarrollador y no lo abre. Quítale la marca de
descarga y ya arranca:
O sin terminal: ábrelo una vez, cierra el aviso y ve a Ajustes del Sistema → Privacidad y seguridad → Abrir igualmente.
xattr -d com.apple.quarantine ./drop-v0.10.1-macos-arm64
- Windows enseña "Windows protegió su PC" (SmartScreen). Pulsa Más información →
Ejecutar de todas formas. O desde PowerShell, antes de abrirlo:
Unblock-File .\drop-v0.10.1-windows-x64.exe
Solo pasa la primera vez: una vez instalado, drop update se actualiza solo, comprobando la
firma, y no vuelve a salir ningún aviso.
Web en producción: https://drop.oloxx.dev
- Enviar:
- Abre la web, arrastra tus archivos o carpetas (o pick a folder) y pulsa open channel. Una carpeta viaja con su árbol; en el receptor, con la File System Access API (Chrome/Edge), se recrea tal cual en la carpeta elegida; en otros navegadores cada archivo baja suelto con su nombre.
- Comparte el código (ej.
4271-lemon-radar-tiger-orbit), que se puede dictar por teléfono, o el enlace equivalente (https://drop.oloxx.dev/#4271-lemon-radar-tiger-orbit). - Para un móvil, pulsa qr: enfoca la pantalla con la cámara y se abre el enlace, sin
teclear nada ni pasárselo por otra aplicación. El QR se genera en la propia página
(
public/shared/qr.js): sigue sin haber peticiones a terceros. - Mantén la pestaña abierta mientras se transfieren los archivos.
- Recibir:
-
El receptor abre el enlace en su navegador, o entra en la web y teclea el código en el campo «…or receive: type the code you were given».
-
Pulsa receive. Dónde acaban los bytes depende del navegador:
Ruta Cuándo Memoria Carpeta elegida (File System Access API) Chrome/Edge, con varios archivos, carpetas o más de 128 MB Constante: se escribe según llega Descarga en streaming por Service Worker ( public/sw.js)Firefox, Safari (macOS e iOS) y Chrome sin carpeta elegida, a partir de 32 MB o sin tamaño conocido Constante: el navegador escribe a Descargas según llega Descarga normal (Blob) Archivos pequeños, o si el worker no está (contexto no seguro, navegador antiguo) El archivo entero en RAM hasta el final En las tres se verifica el SHA-256 al terminar; por el worker, si no cuadra, la descarga se aborta y el navegador la marca como fallida en vez de dejar un archivo corrupto. El worker no cachea nada y solo atiende su propia URL de descarga.
-
- Test de velocidad P2P (
/speed):- Abre
https://drop.oloxx.dev/speedpara medir latencia (RTT), velocidad simétrica de subida/bajada y si la ruta es directa o rebotada por TURN.
- Abre
Abre cualquier terminal y pasa los archivos que quieras enviar:
# Enviar un archivo
drop send pelicula.mkv
# Enviar múltiples archivos a la vez
drop send foto1.jpg foto2.jpg documento.pdf "C:\Descargas\backup.iso"
# Enviar una carpeta entera: llega con su árbol (fotos/verano/playa.jpg)
drop send fotos/Al enviar una carpeta viaja la ruta relativa de cada archivo y el receptor la recrea dentro de
su directorio de destino. Los enlaces simbólicos se saltan y las carpetas vacías no viajan (no
tienen bytes que verificar). El receptor acepta esas rutas solo hacia abajo: un manifiesto
con ../ no degrada al nombre suelto, corta la transferencia.
Salida en terminal:
Preparando envío: 1 archivo(s) · 5.8 GB
✔ Canal abierto.
Código: 4271-lemon-radar-tiger-orbit
Enlace: https://drop.oloxx.dev/#4271-lemon-radar-tiger-orbit
Huella: beef-grit-two (el receptor tiene que ver esta misma por TCP directo)
Díctaselo tal cual, o pásale el enlace. En el otro equipo:
drop recv 4271-lemon-radar-tiger-orbit
█▀▀▀▀▀█ ▄▀ ▀▄█ █▀▀▀▀▀█
█ ███ █ ▀▄▀▄ ▄ █ ███ █ (el QR del enlace, para abrirlo
█ ▀▀▀ █ █ ▀ ▄▀█ █ ▀▀▀ █ desde el móvil con la cámara)
▀▀▀▀▀▀▀ ▀ █ ▀ ▀ ▀▀▀▀▀▀▀
Escanéalo con el móvil para abrir el enlace. (--no-qr lo quita)
Esperando a que el receptor se conecte...
El QR solo se pinta cuando la salida es una terminal (en un log o una tubería no lo lee
nadie) y va con los colores forzados, fondo blanco y tinta negra, para que la cámara vea la
polaridad normal tanto en un tema oscuro como en uno claro. --no-qr o DROP_NO_QR=1 lo
quitan.
Cuando alguien se conecta, drop pregunta antes de servir nada:
Alguien quiere descargar: 192.168.1.42 (TCP directo)
Huella de la sesión: beef-grit-two (tiene que coincidir con la que ve el receptor)
¿Le dejas descargar? (S/n):
Hasta que respondas que sí (basta con pulsar Enter) no sale del equipo ni el nombre
de los archivos. Con --yes (o -y) no pregunta, y en un script sin terminal
interactiva se autoriza solo: bloquear ahí sería colgar el proceso esperando una
tecla que no va a llegar.
Qué es la huella y qué detecta, en
Modelo de seguridad del código.
Acotar la ventana. Un canal abierto sigue sirviendo a quien tenga el código hasta que lo cierras; con códigos que se dictan (y se oyen de paso) conviene poder decir "esto es para una descarga" o "esto caduca en diez minutos":
drop send backup.tar --once # se cierra tras la primera descarga completa
drop send backup.tar --expire 10m # caduca solo: 90s, 10m, 2h (un número suelto son minutos)
drop send backup.tar --once --expire 10mNinguno de los dos corta una descarga a medias: al caducar se deja de aceptar receptores nuevos y el proceso sale cuando termina la que esté en curso. El servidor libera la sala en ese momento, porque la sala vive lo que vive la conexión del emisor.
Límite de ancho de banda. El motor TCP satura Gigabit a propósito, lo cual está muy bien salvo cuando hay alguien más usando la línea:
drop send pelicula.mkv --limit 10M # 500K, 10M, 1.5G: bytes por segundo, en base 1024
drop recv 4271-lemon-radar-tiger-orbit --limit 2MVale en los dos lados. En el emisor es un solo cubo para todos los receptores (lo que sale de este equipo); en el receptor frena la lectura, y el emisor se frena solo por contrapresión (TCP) o por los acuses (relay). La barra y el ETA salen del caudal real, así que siguen siendo ciertos.
Texto y portapapeles. Para mandar un fragmento sin crear un archivo antes:
drop send --text "la clave del wifi es ..." # viaja como message.txt
drop send --clipboard # el portapapeles, como clipboard.txt
drop recv 4271-lemon-radar-tiger-orbit --stdout # lo recibido, a stdout (también: -o -)
drop recv 4271-lemon-radar-tiger-orbit --stdout | pbcopyEl portapapeles se lee con las herramientas del sistema (Get-Clipboard, pbpaste,
wl-paste/xclip/xsel) y si no hay ninguna se dice cuál instalar. Con --stdout los
mensajes y el progreso se van a stderr, y el contenido se vuelca solo cuando el SHA-256 ha
cuadrado: una tubería no se puede rebobinar.
Tuberías. drop send - lee de la entrada estándar y lo manda según llega, sin pasar por un
archivo temporal ni saber cuánto va a ocupar:
tar czf - proyecto/ | drop send - --name proyecto.tgz # sin --name llega como "stdin"
drop recv 4271-lemon-radar-tiger-orbit -o - | tar xzf -
pg_dump base | gzip | drop send - --name base.sql.gzComo no hay total, la barra enseña solo los bytes que van saliendo y la velocidad. Y como lo
leído de una tubería no se puede volver a leer, el envío es de un solo receptor: el canal se
cierra al terminar (como con --once), no hay reanudación, y si el receptor se cae a medias el
emisor sale con error para que vuelvas a lanzar la tubería. En la web el archivo aparece con
tamaño stream y baja igual, verificado al final.
En otro ordenador con drop instalado:
# Usando el código que te han dictado
drop recv 4271-lemon-radar-tiger-orbit
# Da igual cómo lo teclees: mayúsculas, espacios en vez de guiones o prefijos de
# 4 letras. Todo esto es el mismo código:
drop recv "4271 LEMON Radar tiger orbit"
drop recv 4271-lemo-rada-tige-orbi
# O pegando el enlace web completo
drop recv https://drop.oloxx.dev/#4271-lemon-radar-tiger-orbit
# Opcional: especificar carpeta de destino (-o o --out)
drop recv 4271-lemon-radar-tiger-orbit -o D:\Descargas
# Opcional: sobrescribir los archivos que ya existan en el destino
drop recv 4271-lemon-radar-tiger-orbit --overwrite
# Opcional: no reanudar una descarga cortada, empezar de cero
drop recv 4271-lemon-radar-tiger-orbit --no-resume
# Opcional: bajar solo parte del envío (patrones separados por comas)
drop recv 4271-lemon-radar-tiger-orbit --only "*.jpg,*.png"
drop recv 4271-lemon-radar-tiger-orbit --only "fotos/**"Solo parte del envío. Con --only se piden al emisor únicamente los archivos que casen, y
el resto ni viaja. Un patrón sin / se compara con el nombre, esté en la carpeta que esté
(*.jpg); con /, con el final de la ruta (fotos/*.jpg coge viaje/fotos/a.jpg); con /
delante, desde la raíz del envío (/fotos/**). * no cruza carpetas y ** sí. No distingue
mayúsculas. Si no casa nada, drop recv no descarga y enseña qué trae el envío. En la web es lo
mismo con casillas: cada archivo de la oferta tiene la suya y receive baja lo marcado.
Qué pasa si el archivo ya existe: por defecto no se pisa nada. Cada archivo se
escribe primero como nombre.ext.part y solo pasa a llamarse nombre.ext cuando su
SHA-256 cuadra; si ese nombre ya está ocupado, el archivo nuevo se guarda como
nombre (2).ext. Con --overwrite se reemplaza el archivo existente. Una transferencia
que se corta a medias no deja nada con el nombre definitivo.
Si se corta a medias, se reanuda. El .part se queda en disco con lo que llegó, y el
siguiente drop recv con el mismo código sigue desde ahí en vez de empezar de cero, tanto
por TCP directo como por relay. Antes de aceptarlo, el emisor comprueba que ese prefijo es
de verdad el principio de su archivo (compara el SHA-256 de los primeros bytes): si el
.part era de otra cosa, el archivo se descarga entero a nombre (2).ext y el .part no
se toca. Con --no-resume un .part cuenta como nombre ocupado y se empieza de cero. Da igual
que el emisor sea otro drop o una pestaña: los dos comprueban el prefijo.
Compatibilidad: desde la versión 0.5.0 el manifiesto lleva un número de versión de protocolo, así que un receptor 0.5.0+ rechaza con un mensaje explícito a un emisor 0.4.2 o anterior en lugar de escribir archivos corruptos. La reanudación de descargas sube el protocolo a la versión 3: un
drop0.6.x y uno posterior se rechazan mutuamente. La selección de archivos (--only) lo sube a la 5, y ahí se queda: a partir de la 1.0 cualquierdrop1.x habla con cualquier otro y con la web (política de compatibilidad). Si ves un error de versión, actualizadropen los dos equipos condrop update.
Mide la latencia (RTT), velocidad simétrica de subida/bajada y ruta de red (TCP directa o Relay) entre dos clientes CLI:
# En el primer equipo (Anfitrión)
drop speed
# En el segundo equipo (Invitado)
drop speed <código>Cualquiera recibe de cualquiera, en las cuatro combinaciones:
| Emisor → Receptor | Camino | Cifrado | Reanuda un corte |
|---|---|---|---|
| Web → Web | WebRTC DataChannel, directo o por TURN | DTLS | Por archivo, si el receptor elige carpeta: lo que ya está entero en ella no vuelve a bajar. A mitad de un archivo, no |
| CLI → CLI | TCP directo (LAN, UPnP, IPv4 o IPv6) o, si no hay ruta, relay por el servidor | AES-256-GCM con la clave del código | Sí, por TCP y por relay (drop recv con el mismo código). No con drop send -: una tubería no se rebobina |
| CLI → Web | Relay por el servidor (el navegador no habla el TCP del CLI) | AES-256-GCM con la clave del código | Por archivo, como Web → Web |
| Web → CLI | Relay por el servidor (el CLI no habla WebRTC) | AES-256-GCM con la clave del código | Sí: el .part sigue desde donde se quedó, igual que entre dos CLI |
Por qué el navegador no reanuda a mitad de un archivo. File System Access no escribe en el
archivo según llega: escribe en un temporal (.crswap en Chrome) que solo pasa al nombre bueno al
cerrarse. Si la pestaña se cierra o se corta la conexión, ese temporal se tira y no queda nada que
retomar. Un archivo terminado sí queda, y por eso se retoma archivo a archivo: al volver a abrir el
enlace y elegir la misma carpeta, la pestaña hashea lo que ya hay y el emisor solo manda lo que falta
o no cuadra. Sin carpeta (Firefox, Safari, iOS) no hay nada en disco que mirar y se empieza de cero.
- Si envías con
drop sendy el destinatario no tiene la terminal, abre el enlace en Chrome, Edge, Firefox o Safari, o entra en la web y teclea el código: verá los archivos y el botón receive. - Si el canal se abre desde la web y el receptor prefiere la terminal,
drop recv <código>funciona igual: el CLI se presenta como tal al entrar en la sala y la página le sirve por el relay, cifrado, en vez de mandarle una oferta WebRTC. - Por el relay los bytes pasan por el servidor, pero cifrados con la clave que sale de las cuatro palabras: el servidor reenvía ruido. Ver ¿Cómo funciona por dentro?.
drop update # Comprueba y actualiza automáticamente a la última versión de GitHub
drop install # Instala drop en el sistema y lo añade al PATH
drop uninstall # Desinstala drop del sistema y limpia el PATH
drop --version # Muestra la versión instalada
drop --help # Muestra la ayuda de comandosAutocompletado. drop completion <shell> imprime el script y no toca ningún perfil por su
cuenta; se carga así:
eval "$(drop completion bash)" # ~/.bashrc
eval "$(drop completion zsh)" # ~/.zshrc
drop completion fish > ~/.config/fish/completions/drop.fish # fish
drop completion powershell | Out-String | Invoke-Expression # $PROFILECompleta las órdenes, los flags que valen para cada una, las carpetas tras -o y los archivos
tras send.
- Descubrimiento LAN instantáneo: Emite pings por broadcast UDP (puerto
42424). En la misma red Wi-Fi o cable, los equipos se encuentran en < 10 milisegundos y transfieren por IP privada local sin salir a internet. - Sockets TCP Directos: Utiliza
socket.setNoDelay(true)con búferes de lectura/escritura de 2–4 MB en streaming continuo. - Cifrado E2EE nativo: Cifrado simétrico AES-256-GCM con aceleración hardware
AES-NI. La clave sale de las cuatro palabras del código pasadas porscrypt(ver abajo), nunca del identificador de sala. - El relay también va cifrado: cuando no hay ruta TCP directa (NAT estricta, o el receptor es un
navegador) los bytes pasan por el servidor, pero cifrados con la misma clave: cada trozo y cada
marco de control van en AES-256-GCM y el servidor reenvía ruido. El navegador deriva la misma clave
con una implementación propia de
scrypt(public/shared/scrypt.js), y la prueba de conocimiento del código que le manda al emisor es un HMAC con esa clave, no un hash de las palabras: un servidor que la vea pasar no tiene nada barato que atacar offline.
- Protocolo mínimo: Control en JSON (
manifest,accept,start,ack,end,done) y datos en trozos binarios continuos. Está especificado entero, señalización incluida, endocs/PROTOCOL.md. - Control de flujo reactivo: Evita desbordar la memoria pausando la lectura al superar 8 MB en el búfer de envío y reanudando al bajar de 1 MB.
- Cadena multi-receptor (Fanout Chain): Cuando varios amigos descargan a la vez, se organizan en cadena (
Emisor → A → B → C). El emisor sube una sola copia de los datos, ahorrando ancho de banda de subida.
El código es 4271-lemon-radar-tiger-orbit y son dos cosas distintas pegadas con un guion:
| Parte | Qué es | ¿Sale de tu equipo? |
|---|---|---|
4271 |
Identificador público de sala, lo reparte el servidor | Sí: al servidor y, hasheado, al broadcast UDP de la LAN |
lemon-radar-tiger-orbit |
Secreto compartido, lo sortea tu cliente | Nunca. Ni en claro, ni hasheado, ni al servidor, ni por UDP |
- Entropía: 4 palabras de la lista BIP-39 en inglés (2048 palabras, licencia CC0,
copia íntegra en
public/shared/wordlist.js) = 44 bits exactos. Se eligió BIP-39 porque 2048 = 2¹¹ da 11 bits limpios por palabra y porque sus prefijos de 4 letras son únicos, que es lo que permite corregir erratas al teclear. - Derivación de clave: la clave AES-256-GCM sale de las palabras por
scrypt(N=2¹⁵, r=8, p=1 → 32 MB y ~62 ms medidos), con el identificador de sala como sal. No se usa HKDF a propósito: con 44 bits, un hash rápido se rompería por fuerza bruta en horas; con scrypt haría falta ~3,5 × 10¹⁰ años-CPU. - Lo que ve el servidor:
4271y nada más. No puede descifrar, y tampoco puede atacar el secreto offline porque no tiene ningún verificador de él. - Lo que ve tu vecino de Wi-Fi: el paquete de descubrimiento UDP lleva un hash del
identificador público. Aprende que hay una sala
4271en tal IP y puerto; sin las palabras, AES-GCM le rechaza el primer paquete. - Lo que NO cubre: los identificadores de sala son 10.000 y se pueden probar. El servidor limita los intentos fallidos por IP y cierra la sala si el emisor denuncia varios receptores que no saben el secreto, pero eso encarece el barrido, no lo impide. Quien acierte una sala no obtiene ni los archivos ni sus nombres: el emisor le pide antes una prueba de conocimiento del secreto, y además tiene que autorizar la descarga a mano. Sigue sin haber PAKE (SPAKE2/CPace), que no se implementa a mano sin auditar: contra un man in the middle activo con control del servidor lo que hay es la huella de sesión, que se compara a ojo.
Los dos extremos muestran tres palabras — beef-grit-two — sacadas de lo que se ha negociado
de verdad. Si no coinciden, hay alguien en medio. Se comparan por otro canal: una llamada,
un mensaje, estar en la misma habitación.
| Ruta | De dónde sale la huella | Qué detecta |
|---|---|---|
| Web ↔ Web (WebRTC) | Los fingerprints DTLS de los dos extremos | Un servidor que sustituya el SDP para hablar DTLS con cada lado por separado. Es el ataque real que cubre |
| CLI ↔ CLI (TCP directo) | La clave AES ya derivada con scrypt | Que los dos estén en la misma transferencia. Aquí un MITM ya era imposible: sin las palabras, AES-GCM rechaza el primer paquete |
| Cualquier ruta por relay (CLI → CLI o CLI → navegador) | La clave AES derivada con scrypt, igual que por TCP directo | Que los dos hayan derivado la misma clave: por esta ruta los bytes pasan por el servidor, pero cifrados con ella. El servidor no puede leerlos ni fabricar una huella que cuadre |
La huella no viaja por el cable (si viajase, el de en medio la cambiaría al vuelo) y no
lleva dentro las palabras del código: entra material de clave, no el secreto, para que leerla
en voz alta no regale un verificador offline de 44 bits. El diseño completo está en
public/shared/sas.js.
El diseño completo, con el razonamiento y los límites, está comentado en la cabecera de
public/shared/codes.js.
La web confía en el app.js que descarga, como toda web: un servidor malicioso podría servir
otro. drop verify-web lo comprueba sin fiarse del servidor:
drop verify-web # https://drop.oloxx.dev
drop verify-web https://mi-drop.example # cualquier otra instanciaEl servidor dice qué commit sirve (/version), la API de GitHub da el hash de cada archivo de
public/ en ese commit del repositorio público, y se compara con lo que el servidor entrega de
verdad, archivo a archivo. Si algo no cuadra, o el commit no existe en el repositorio, sale con
error. Lo que no puede decir es que el servidor sirva lo mismo a todo el mundo: comprueba lo que
te ha servido a ti. Con GITHUB_TOKEN en el entorno usa tu cuota de la API en vez de la anónima.
Mientras la versión mayor sea 0, una versión menor puede romper el protocolo, y cuando lo hace
se dice en el CHANGELOG. Desde la 1.0 manda la
política de compatibilidad. Hoy:
- Dos
droptienen que compartirPROTOCOL_VERSION(la 5, la de toda la 1.x); si no, se rechazan con un mensaje que pidedrop updateen vez de entenderse a medias. La web comprueba lo mismo al recibir de un CLI. - Los tokens de la v0.3.5 (
T_9q_4uzB9iJAf8x, 96 bits que además eran la clave de cifrado) dejaron de aceptarse en la v0.8.0: el servidor contestaVERSIONa un cliente que no pide códigos memorizables, y ni el CLI ni la web los reconocen ya como código.
- Node.js >= 18
# Instalar dependencias
npm install
# Iniciar servidor local de desarrollo (http://localhost:3000)
npm run dev
# Ejecutar el CLI en modo desarrollo
npm run cli -- send mi_archivo.zip
# Ejecutar la suite de tests (levanta su propio servidor, no hace falta nada mas)
npm test
# Benchmarks de velocidad
npm run bench:cli # Benchmark del motor TCP nativo (~110 MB/s)
npm run bench # Benchmark WebRTC en navegador (~15 MB/s)
npm run bench:fanout # Benchmark de cadena multi-receptorEl script scripts/build-cross.mjs permite compilar los binarios de todas las plataformas desde cualquier sistema operativo utilizando Node SEA (Single Executable Application):
npm run build:exe # Compila dist/drop-windows-x64.exe (Windows x64)
npm run build:linux # Compila dist/drop-linux-x64 (Linux x64)
npm run build:arm # Compila dist/drop-linux-arm64 (Linux ARM64 / Raspberry Pi)
npm run build:macos # Compila dist/drop-macos-arm64 (macOS Apple Silicon)
npm run build:all # Compila todas las plataformas a la vezLos binarios base de Node se descargan de nodejs.org y se comprueban contra el
SHASUMS256.txt que se publica junto a ellos antes de inyectarles nada, también los que ya
están en la caché local. Si un hash no cuadra, el fichero se borra y la compilación se detiene:
ese binario es el que acaba en las releases.
El servidor actúa únicamente como guía de señalización (emparejamiento) y nunca almacena archivos.
Para desplegar tu propia instancia en un VPS (ej. Oracle Cloud Always Free):
cp .env.example .env
docker compose up -d --buildLevanta el servidor Node.js, un reverse proxy Caddy con certificados SSL automáticos y un servidor TURN (coturn) para sortear NATs estrictas. Guía detallada en DEPLOY-VPS.md.
El servidor solo acepta WebSockets de navegador desde su propio dominio (DROP_DOMAIN) y
localhost, para que una web cualquiera no pueda abrir salas con el navegador de quien la visita.
Si sirves el frontend desde otro sitio, añade el origen con DROP_ALLOWED_ORIGINS. Las
conexiones sin cabecera Origin —el CLI— no se ven afectadas.
Las respuestas llevan una CSP ajustada a lo que la web usa de verdad —ni scripts ni estilos
en línea, ni una sola petición a terceros—, además de X-Content-Type-Options: nosniff,
Referrer-Policy: no-referrer y Permissions-Policy sin cámara, micrófono ni ubicación. HSTS lo
pone Caddy, que es donde acaba el TLS. El contenedor corre como usuario sin privilegios y declara
un HEALTHCHECK contra /healthz.
Las convenciones del proyecto (idiomas, estilo de comentarios, formato de commits) y cómo montar el entorno están en CONTRIBUTING.md. El historial de versiones, en CHANGELOG.md. Lo que falta para la 1.0, en ROADMAP.md.
Apache License 2.0. Puedes usar, modificar y redistribuir drop, incluso comercialmente, conservando el aviso de copyright y la licencia, e indicando los cambios que hagas. La licencia incluye además una concesión expresa de patentes.