npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ciphermesh

v2.9.0

Published

Secure terminal chat for the local network (LAN) with real end-to-end encryption (E2EE) using libsodium

Readme

 ██████╗██╗██████╗ ██╗  ██╗███████╗██████╗ ███╗   ███╗███████╗███████╗██╗  ██╗
██╔════╝██║██╔══██╗██║  ██║██╔════╝██╔══██╗████╗ ████║██╔════╝██╔════╝██║  ██║
██║     ██║██████╔╝███████║█████╗  ██████╔╝██╔████╔██║█████╗  ███████╗███████║
██║     ██║██╔═══╝ ██╔══██║██╔══╝  ██╔══██╗██║╚██╔╝██║██╔══╝  ╚════██║██╔══██║
╚██████╗██║██║     ██║  ██║███████╗██║  ██║██║ ╚═╝ ██║███████╗███████║██║  ██║
 ╚═════╝╚═╝╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═╝     ╚═╝╚══════╝╚══════╝╚═╝  ╚═╝

Chat de terminal com criptografia ponta-a-ponta — o servidor não lê uma palavra.

CI License: MIT Node Crypto Site

ciphermesh.de — o site, e o hub público em que qualquer pessoa pode entrar.

🇺🇸 Read in English · Guia de Setup · Arquitetura · Política de Segurança · Termos do Hub · Como contribuir


 Você ──[payload cifrado]──▶  Relay (cego)  ──[payload cifrado]──▶  Amigo
        Curve25519 + XSalsa20-Poly1305 · Double Ratchet · zero-knowledge

CipherMesh é um chat de terminal onde a criptografia é o produto. As chaves vivem em páginas de memória travadas, cada mensagem usa uma chave nova do ratchet, e o servidor de relay só enxerga ciphertext — não lê, não altera, não forja nada. Funciona na sua LAN de cara, e pela internet com Tailscale (sem port forwarding, imune a CGNAT).

✨ Destaques

| | Feature | Resumo | | --- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 🔐 | E2EE de verdade | Curve25519 + XSalsa20-Poly1305 via libsodium, chaves em sodium_malloc — nunca tocam o disco | | 🔄 | Perfect Forward Secrecy | Double Ratchet: uma chave por mensagem — comprometer hoje ≠ ler ontem | | 🛡️ | Pós-quântico híbrido | X25519 + ML-KEM-768 misturado na raiz do ratchet — vence o "grava hoje, decifra depois" mantendo segurança ≥ à clássica (detalhes) | | 🕶️ | Resistência a metadados | Sealed sender — o relay nunca vê quem enviou a mensagem — + padding de comprimento em buckets fixos em todo ciphertext e cover traffic opcional (/cover) | | 🕵️ | TOFU + SAS | Alarme de troca de chave (MITM), código de 6 dígitos verificável por voz e badges de confiança ✓/✗ inline ao lado dos nomes | | 🌐 | LAN e internet | Detecta Tailscale sozinho e mostra o endereço alcançável no banner | | 📨 | Convites com QR | /invite gera uma string ciphermesh:// + QR — colou, caiu na sala certa | | ✓✓ | Read receipts cifrados | O ✓✓ viaja como ciphertext comum — o servidor não distingue de mensagem | | 🗂️ | Histórico local cifrado | Opt-in (só com passphrase), Argon2id + XSalsa20-Poly1305, /search e /export | | 🖼️ | Preview de imagens | Fotos recebidas renderizam no chat em half-blocks coloridos | | 📎 | Transferências com resume | Chunks perdidos são re-pedidos; reconexão retoma de onde parou | | 💬 | Cara de app moderno | Suas mensagens à direita, avatar de emoji por usuário, reply com citação, :fire: → 🔥 | | 🎞️ | Interface animada | Splash na abertura, spinner de reconexão, barra de transferência viva (shimmer + ETA), cadeado fechando no handshake e um selo pulsante "novas mensagens ↓" | | 👻 | Deniable e efêmeras | Modo de negação plausível (crypto simétrica); mensagens efêmeras queimam caractere a caractere ao expirar | | 🔒 | Salas privadas | /create <sala> <senha> — zero-knowledge: a senha nunca sai da sua máquina (Argon2id → challenge-response Ed25519) e o conteúdo da sala ganha uma camada simétrica extra que nem um relay malicioso atravessa | | 🗂️ | Buffers multi-sala | Fique em várias salas ao mesmo tempo — Alt+1..9 alterna, com não-lidas por sala. A qual sala cada mensagem pertence viaja dentro do payload cifrado: o relay nunca fica sabendo | | 🩺 | Ele se explica sozinho | /doctor diagnostica uma conexão que falha camada por camada — endereço, DNS, TCP, TLS, protocolo — e diz o que fazer em cada falha | | 🔐 | Trava de tela | /lock e /autolock põem a sessão atrás da sua passphrase quando você sai da frente; o /panic continua ali para o pior momento | | 🛰️ | Modo P2P sem servidor | Descoberta de peers via mDNS na LAN — sem relay nenhum, e com quase o mesmo conjunto de comandos | | 🧩 | Plugins | Solta um arquivo JS em ~/.ciphermesh/plugins e ganha comandos novos — exemplos /roll e /poll inclusos (API de plugins) |

🚀 Começando

Converse com alguém em menos de um minuto — sem instalar, sem conta, sem servidor próprio:

npx ciphermesh@latest

No prompt Server, digite ciphermesh.de — um relay público que qualquer pessoa pode usar. Combine um nome de sala com quem você quer conversar (/join nossasala) e pronto: vocês estão conversando com criptografia ponta-a-ponta.

O hub é mantido como projeto pessoal sob estes termos. É um relay zero-knowledge: quem o opera não consegue ler suas mensagens — isso é uma propriedade do software, não uma promessa. Prefere o seu próprio? Todos os comandos abaixo funcionam igual num relay que você hospeda.

Outros modos:

npx ciphermesh server   # rode o seu próprio relay
npx ciphermesh p2p      # sem servidor, descoberta por mDNS na LAN

macOS/Linux com Homebrew (veja Formula/ciphermesh.rb):

brew tap felipekreulich/ciphermesh
brew install ciphermesh

Ou pelo código-fonte:

git clone https://github.com/FelipeKreulich/secret-chat-lan.git
cd secret-chat-lan
npm install

Quem hospeda (uma máquina roda o relay):

npm run server          # ou: docker compose up -d  |  npx ciphermesh server

Prefere imagem pronta? Baixe o relay do GHCR (publicado a cada release):

docker run -p 3600:3600 ghcr.io/felipekreulich/secret-chat-lan:latest

Vai hospedar publicamente? A pasta deploy/ tem um setup com Caddy + Docker que pega certificado Let's Encrypt sozinho — aí os clientes verificam o servidor contra uma CA de verdade (sem janela de trust-on-first-use), e um host que já apresentou certificado válido nunca pode ser rebaixado silenciosamente para um self-signed.

Sem Node nenhum? Binários standalone para macOS e Linux (arm64/x64) — baixe do último release, chmod +x, rode. Nada para instalar, nem Node.

Pegue os binários do release mais recente. Os publicados antes da v2.7.2 nunca embutiram o addon nativo e só rodavam na máquina que os construiu, então aqueles anexos foram removidos.

| Binário | O que é | | -------------------------------- | ------------------------------------------------------------------------------------------ | | ciphermesh-<plataforma> | Tudo: cliente, relay e P2P. ciphermesh server e ciphermesh p2p funcionam igual ao npm. | | ciphermesh-server-<plataforma> | Só o relay, para quem hospeda e não quer mais nada na máquina. |

Todo mundo (incluindo quem hospeda):

npm run client          # nickname → passphrase (opcional) → endereço do servidor

Na mesma rede, use o IP da LAN que aparece no banner do servidor (192.168.x.x:3600). Pela internet, instalem Tailscale dos dois lados e usem o endereço Internet do banner — passo a passo completo em docs/SETUP.md.

Já está no chat? Rode /invite <seu-ip>:3600 e mande a string (ou o QR) pra quem você quiser puxar pra conversa.

Sem servidor nenhum? npm run p2p — os peers se encontram via mDNS. O modo P2P agora fala quase o mesmo conjunto de comandos do cliente relay (presença, /lock, /contacts, /mentions, /topic, histórico cifrado e mais); só /invite, /create e /nick são específicos do relay por natureza.

🌐 A comunidade fica no ciphermesh.de

Durante muito tempo, usar o CipherMesh exigia já conhecer alguém que rodasse um relay. Isso acabou: ciphermesh.de é um hub público, gratuito, aberto a qualquer pessoa e sempre no ar. Ninguém precisa combinar quem vai subir o servidor.

npx ciphermesh@latest
# Server: ciphermesh.de
# Room:   general
  • A general é a porta de entrada. É a sala padrão — conecte e diga oi se você só quer ver quem está por perto.
  • Qualquer sala, aberta por qualquer um. Escolha um nome, avise quem você quer lá dentro e comece a conversar. Sem conta, sem convite, sem lista de espera.
  • Privada na hora que você quiser. Ponha uma senha e a sala é sua. A senha nunca chega ao servidor — ele guarda só um verificador derivado com Argon2id, que não dá para reverter.
  • Nada sobrevive à conversa. A sala existe enquanto alguém está dentro dela. Quando a última pessoa sai, a sala e tudo o que foi dito nela desaparecem.

Manter o hub não transforma quem o opera em leitor: ele é zero-knowledge como qualquer outro relay do CipherMesh — a única diferença é que este nunca dorme. O uso é regido pelos termos.

Para chamar gente: /invite imprime uma string de entrada e um QR code, e /rooms mostra o que está no ar.

Para que o hub existe. Ele existe para qualquer pessoa poder experimentar o CipherMesh e encontrar outras pessoas que o usam sem precisar subir um servidor antes. É um ponto de encontro, não um serviço de comunicação de uso geral — as salas não são casa de ninguém, não há contas, e nada fica entre sessões.

Se você precisa de um relay que seja seu, suba um. Ele responde a você, não depende da disponibilidade de mais ninguém, e não faz suas conversas passarem por uma máquina administrada por um estranho. A pasta deploy/ tem o setup Docker pronto. Para o que é importante essa é a melhor resposta — e é aquela para a qual este software foi feito.

💬 Comandos

| Comando | Descrição | | ----------------------------- | ----------------------------------------------------------------------- | | /help | Todos os comandos | | /tips | Mostra uma dica rotativa de segurança/UX | | /users | Quem está online (com away/status) | | /msg <nick> <texto> | Mensagem privada (DM) | | /reply <texto> | Responde citando a última mensagem recebida | | /me <ação> | Ação em terceira pessoa — «felipe está compilando» | | /watch [add\|remove\|clear] | Alerta quando uma palavra aparece em qualquer sala, como uma menção | | /invite [host:porta] | Gera convite ciphermesh:// + QR code | | /nick <novo> | Troca de apelido (antes de entrar — recupera de "apelido em uso") | | /quit | Sair |

| Comando | Descrição | | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | /join <sala> [senha] | Abre a sala como um novo buffer — você continua nas outras (estilo IRC) | | /leave [sala] | Sai de uma sala; o buffer fecha (a última sala é protegida) | | /create <sala> <senha> | Cria uma sala privada 🔒 — veja abaixo | | /rooms | Lista salas (🔒 marca as privadas) | | /room | Sala atual + sua lista de buffers | | /topic [texto\|clear] | Mostra ou define o assunto da sala — aparece na barra de status e é sincronizado para quem entra depois | | /owner | Dono da sala | | /kick /mute /ban | Moderação (dono da sala) — presa à chave pública, então trocar de apelido não desfaz um ban | | /block /unblock /blocklist | Pare de ver alguém, só para você. Nada é enviado, o relay nunca fica sabendo e a pessoa não é avisada — por isso qualquer um pode usar, inclusive na general, que não tem dono. Funciona no P2P também, onde não há moderação nenhuma. |

Buffers: esteja em várias salas ao mesmo tempo — Alt+1..9 alterna, e a barra de status mostra [1:general] [2:dev •3] com não-lidas por sala. Como o relay é cego (sealed sender), a qual sala cada mensagem pertence viaja dentro do payload cifrado — o servidor nunca fica sabendo.

Salas privadas são zero-knowledge: a senha nunca sai da sua máquina. Ao entrar, o cliente deriva uma chave Ed25519 da senha (Argon2id) e responde um desafio do servidor com uma assinatura — o servidor guarda só um verificador, em memória, que morre quando a última pessoa sai (salas são sempre efêmeras). Além disso, tudo que é dito numa sala privada carrega uma camada simétrica extra derivada da senha: mesmo um relay malicioso que deixasse alguém entrar sem verificar não leria uma palavra. Combine a senha por outro canal.

| Comando | Descrição | | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | /fingerprint [nick] | Fingerprint + um randomart determinístico da chave | | /verify <nick> | Código SAS (~40 bits) + QR + randomart da chave para verificar | | /verify-confirm <nick> | Marca o peer como verificado | | /backup [caminho] | Backup cifrado da identidade + peers verificados (restaura no startup) | | /trust <nick> / /trustlist | Aceita chave nova / status de confiança | | /contacts [add\|remove\|all] | Agenda — apelidos persistentes nos registros de confiança ("esse fingerprint é o João"); aparece no /users e viaja no backup de identidade | | /deniable [on\|off] | Modo de negação plausível | | /lock / /autolock <min\|off> | Trava a tela atrás da passphrase da sessão — na mão ou após inatividade (autoLock no config). Privacidade para o "saí um minuto"; o /panic é para o pior minuto | | /panic [sim] | Wipe de coação — apaga com segurança todos os segredos do disco (sessão, histórico, confiança, chaves) e sai | | /cover [on\|constant\|off] | Cover traffic — on = iscas com jitter, constant = canal de taxa constante | | /theme [nome] | Tema de cores dos nicks: neon, matrix, mono, sunset, ocean | | /ephemeral <30s\|5m\|1h\|off> | Mensagens autodestrutivas | | /receipts [on\|off] | Envio de confirmação de leitura (✓✓) | | /audit [n] | Log de auditoria local |

Um verde ao lado de um nome indica um peer verificado por SAS; um vermelho sinaliza uma chave que mudou desde a última vez (possível MITM). Um peer novo não-verificado dispara um lembrete único para /verify.

| Comando | Descrição | | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | /file <caminho> | Oferece arquivo (≤ 50MB) — o destinatário precisa dar /accept; retoma | | /voice [seg] | Grava e envia nota de voz cifrada (precisa de sox/ffmpeg; default 10s) | | /play [caminho] | Toca a última nota de voz recebida (afplay/sox/ffplay) | | /accept [id] / /reject [id] | Aceita / recusa uma oferta de arquivo recebida | | /img [caminho] | Renderiza a última imagem recebida em alta resolução (kitty/iTerm2) | | /retention <7d\|24h\|30m> | Purga o histórico local mais antigo que o tempo dado | | /search <termo> | Busca no histórico local cifrado (em disco, entre sessões) | | /find [termo]Ctrl+F | Busca no histórico da sala na tela e, com Enter, salta para a mensagem destacada | | /doctor [host:porta] | Diagnostica por que a conexão falha: endereço, DNS, porta TCP, TLS (CA ou self-signed) e versão de protocolo — cada falha com o que fazer | | /history [n] | Últimas n mensagens do histórico | | /export [caminho] | Exporta o histórico em .txt ou .json (texto plano!) |

| Comando | Descrição | | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | /away [motivo] / /back | Marca/remove ausência — enquanto ausente, não-lidas são contadas ([away · N new]) e o /back mostra um resumo | | /mentions [n] | Menções recentes a você na sessão (quem, onde, quando) | | /status <texto\|off> | Status livre — emoji à vontade (/status :fire: codando) | | /react <emoji> | Reage à última mensagem — o emoji aparece na própria mensagem, com contagem quando várias pessoas reagem | | /edit /delete | Edita ou apaga sua última mensagem — a linha original é reescrita no lugar (marcada (edited)) ou vira uma lápide, em vez de uma linha nova que você precisa juntar mentalmente à original | | /pin /unpin /pins | Fixa mensagens | | /sound /notify | Notificações sonoras / desktop | | /dnd [on\|off\|mentions\|HH:MM-HH:MM] | Não perturbe, só menções, ou horário silencioso | | /clear | Limpa o chat |

Digitar :fire: em qualquer lugar vira 🔥 (Tab autocompleta shortcodes). Ctrl+K abre uma paleta de comandos fuzzy, Ctrl+E um seletor de emoji. PageUp/PageDown rolam o histórico. Alt+Enter (ou Shift+Enter onde o terminal suporta, além de Ctrl+J) insere uma nova linha para mensagens de várias linhas; Enter envia. Colar texto multi-linha (código incluso) preserva as quebras — cola, confere, Enter. Markdown funciona: `código`, negrito, itálico, links, além de blocos de código ``` e | tabelas |. Imagens recebidas têm preview inline (half-blocks) e renderizam em alta resolução com /img no kitty/iTerm2. Separadores de dia e agrupamento de mensagens deixam o log limpo.

Primeira execução & arquivo de config

Na primeiríssima execução, um wizard de 30 segundos te guia por nickname, tema de cores e servidor padrão (com um mini-curso de 3 linhas de como a criptografia funciona) e salva tudo — das próximas vezes você cai direto no chat. Refaça quando quiser com ciphermesh --setup; pule em scripts/CI com --no-onboard.

O CipherMesh também lembra a sua última sessão: o prompt de servidor passa a ter como padrão onde você estava, e depois de conectar você volta sozinho para a última sala (salas privadas ficam de fora — o nome delas nunca toca o disco). Para começar do zero: ciphermesh --fresh.

O wizard grava o ~/.ciphermesh/config.json — que você também pode editar na mão. Todas as chaves são opcionais (chaves desconhecidas são ignoradas):

{
  "nickname": "felipe",
  "server": "wss://100.x.y.z:3600",
  "sound": false,
  "notify": true,
  "receipts": true,
  "deniable": false,
  "cover": "constant",
  "theme": "matrix",
  "autoAway": 10,
  "autoLock": 5,
  "dnd": "22:00-08:00"
}

nickname/server pré-preenchem os prompts (Enter aceita); o resto é aplicado na inicialização como se você tivesse rodado o comando /sound, /cover, /theme, … correspondente. Temas: neon (padrão), matrix, mono, sunset, ocean.

🔒 Modelo de segurança

  • O relay é zero-knowledge: roteia ciphertext com padding anti-metadados e nada mais. Read receipts, reações, presença — tudo é ciphertext indistinguível pro servidor.
  • Resistência a análise de tráfego: todo ciphertext é paddado até buckets de tamanho fixo (o relay não lê o comprimento da mensagem); chunks de arquivo são paddados a um tamanho uniforme, então o tamanho exato do arquivo também não vaza. /cover on adiciona iscas com jitter e /cover constant faz suas mensagens saírem por um canal de taxa constante (iscas preenchem os slots ociosos), pra ele não distinguir conversa ativa de ociosa. Iscas são descartadas em silêncio.
  • Anti-replay com nonces monotônicos, rotação de chaves a cada hora com janela de graça, limpeza segura de memória (sodium_memzero) após o uso.
  • Wipe de coação (/panic sim): sobrescreve e apaga todos os segredos do disco (estado da sessão, histórico, confiança, auditoria), zera as chaves em memória e sai sem salvar — para um device perdido ou apreendido.
  • Estado de sessão e histórico local são cifrados em repouso com Argon2id + XSalsa20-Poly1305 — sem passphrase, nada persiste.
  • Pós-quântico híbrido: cada sessão mistura um segredo ML-KEM-768 na raiz do ratchet na inicialização, então tráfego gravado hoje continua ilegível para um adversário quântico futuro. Ele é somado ao X25519, nunca o substitui — a segurança é no mínimo a clássica. O /trustlist mostra [PQ].
  • Salas privadas nunca enviam a senha a lugar nenhum: ela deriva uma chave Ed25519 (Argon2id) que responde a um desafio do servidor, e o conteúdo da sala carrega uma camada simétrica extra — um relay malicioso que deixasse alguém entrar sem verificar ainda assim não leria uma palavra.
  • Análise de ameaças e detalhes do protocolo: docs/ARCHITECTURE.md. Achou algo? Veja SECURITY.md.

🧪 Desenvolvimento

npm run server:dev      # relay com auto-reload
npm test                # 418 testes (crypto, ratchet, fuzz, controllers, transferências…)
npm run validate        # lint + prettier + testes — o mesmo que o CI roda

O CI roda em todo push/PR (Node 20 e 22). Tags v* disparam testes + GitHub Release automaticamente.

📄 Licença

MIT — faça coisas boas com isso.