Skip to content

Latest commit

 

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pass-secrets

ENGLISH VERSION

Uma extensão para o password-store (pass) que obscurece a árvore de diretórios e nomes de serviços mantendo a estrutura original do pass.

Diferente do pass-tomb (que necessita de volumes criptografados via Loopback e privilégios de superusuário), o pass-secrets utiliza mapeamentos criptografados (.secrets.gpg e .mask.gpg) baseados na chave GPG de cada diretório. Os serviços e pastas usam codinomes aleatórios, e a associação real é guardada no mapa por identidade.

Versão atual: 2.6.0


💡 Como Funciona?

No pass tradicional, os nomes de pastas e arquivos são visíveis no sistema de arquivos. O pass-secrets permite que você renomeie subdiretórios e entradas reais para codinomes aleatórios (ex: Zovar/Kelip.gpg) e mantenha um mapa criptografado associando o codinome ao serviço real.

🛡️ Identidades e Isolamento de Confiança

Uma identidade é qualquer diretório na árvore do pass que possua seu próprio arquivo .gpg-id, independente da profundidade. Nomes de identidade devem ser únicos em toda a árvore. Dois diretórios com .gpg-id e o mesmo nome tornam o comando ambíguo e são recusados.

  • Fronteira de Confiança: Uma identidade aninhada dentro de outra NÃO herda as chaves da identidade pai.
  • Isolamento Total: Comprometer a chave da identidade pai não expõe o conteúdo da filha.
  • Proteção contra cruzamento de fronteira: generate e namegen recusam qualquer bloco/caminho que atravesse o diretório de outra identidade aninhada — sem essa checagem, uma senha poderia ser cifrada com a chave da identidade errada.

🔑 Assinatura de .gpg-id (opcional)

Se PASSWORD_STORE_SIGNING_KEY estiver configurado (mesma variável usada pelo pass nativo), o pass-secrets exige um .gpg-id.sig válido antes de aceitar os destinatários de uma identidade — bloqueando substituição ou injeção de chave no .gpg-id. Sem a variável configurada, o comportamento é idêntico ao pass puro (sem verificação).


🛠️ Instalação

# 1. Crie o diretório de extensões do pass (caso não exista)
mkdir -p "${PASSWORD_STORE_EXTENSIONS_DIR:-$HOME/.password-store/.extensions}"

# 2. Copie o script para a pasta de extensões
cp secrets.bash "${PASSWORD_STORE_EXTENSIONS_DIR:-$HOME/.password-store/.extensions}/secrets.bash"

# 3. Torne o script executável
chmod +x "${PASSWORD_STORE_EXTENSIONS_DIR:-$HOME/.password-store/.extensions}/secrets.bash"

# 4. Habilite extensões no seu shell (.bashrc, .zshrc, etc.)
export PASSWORD_STORE_ENABLE_EXTENSIONS=true

🚀 Uso e Comandos

Todos os comandos seguem a sintaxe: pass secrets <identidade> <subcomando> [argumentos].

🔍 Consultas no Mapa (.secrets.gpg)

Comando Descrição
pass secrets <id> dir <bloco> Lista entradas cujo caminho começa com o bloco informado.
pass secrets <id> word <termo> [contexto] Busca um termo no mapa visualizando linhas de contexto (grep -C).
pass secrets <id> count <bloco> Retorna a contagem de entradas sob o bloco especificado.
pass secrets <id> struct Exibe a estrutura real de codinomes em disco via scan (sem decifrar).
pass secrets <id> version Exibe a versão instalada da extensão.

✏️ Gerenciamento e Reconciliação

Comando Descrição
pass secrets <id> add <caminho> Associa manualmente um codinome já existente. O nome real é pedido via prompt, nunca por argumento, para evitar exposição no histórico do shell.
pass secrets <id> edit Edita o .secrets.gpg decifrando para um arquivo temporário na memória (via /dev/shm), abre com o seu $EDITOR e recifra. Não depende de ferramentas de terceiros (o suporte via vim-gnupg foi removido).
pass secrets <id> check Audita o mapa contra a árvore real de arquivos, como somente leitura (equivale a rebuild --dry-run). Além de novas/órfãs, reporta colisão global de nomes de identidade, entradas de mask apontando pra diretório inexistente, e nomes reais duplicados entre codinomes diferentes.
pass secrets <id> rebuild [--yes] [--prune] Varre a árvore real e reconcilia o mapa.
  • Flags do rebuild:
    • --yes: Não pergunta o nome real para novas entradas (insere como (pendente)).
    • --prune: Remove entradas órfãs do mapa.

🔐 Geração de Codinomes

Comando Descrição
pass secrets <id> namegen [bloco] [-n tamanho] [-u quantidade] Sugere codinomes livres de um tamanho especificado, sem criar arquivos. Checa colisões apenas dentro da mesma identidade. Blocos que atravessam identidades aninhadas são recusados, mesma proteção do generate abaixo.
pass secrets <id> generate [bloco] [tamanho] [flags] Gera um codinome livre e já cria a entrada real via comando nativo pass generate (repassando as [flags]). Não registra a associação de nome, exigindo o uso de add posteriormente. Blocos que atravessam identidades aninhadas são recusados para evitar cifrar com a chave GPG errada.

🎭 Gerenciamento de Aliases e Máscaras (.mask.gpg)

O mapa .mask.gpg permite associar aliases (ex: e-mails descartáveis) a diretórios em uma relação muitos-para-muitos (many-to-many).

Comando Descrição
pass secrets <id> mask add <dir> Associa um alias de e-mail a um diretório. O alias é pedido via prompt interativo em vez de argumento.
pass secrets <id> mask dir <dir> Lista os aliases associados a um diretório.
pass secrets <id> mask word <termo> [ctx] Busca um alias ou diretório no .mask.gpg.
pass secrets <id> mask list Lista todo o conteúdo do .mask.gpg.
pass secrets <id> mask edit Edita o .mask.gpg utilizando o mesmo mecanismo seguro do comando edit principal.

⚠️ Comportamento em contexto não-interativo (scripts, cron, automação)

O nome real (add) e o alias (mask add) nunca são aceitos como argumento — só via prompt, para não ficarem em ~/.bash_history ou visíveis via ps aux. Isso tem uma consequência direta em automação: onde o script precisaria de uma confirmação humana real, ele recusa prosseguir em vez de assumir uma resposta padrão silenciosamente.

  • pass secrets <id> add <caminho> sobre um caminho já associado: exige confirmação interativa ([y/N]). Fora de um terminal, é recusado — nunca sobrescreve silenciosamente.
  • pass secrets <id> rebuild sem --yes: pergunta o nome real de cada entrada nova. Se a entrada padrão terminar (EOF) antes de responder, o comando morre com erro em vez de gravar (pendente) silenciosamente — evita confundir "ninguém respondeu" com "usuário aceitou o padrão". Use --yes explicitamente para automação.
  • pass secrets <id> edit / mask edit: se a cifragem falhar (ex.: .gpg-id corrompido ou apontando pra chave inexistente) e a entrada não for interativa, o comando morre imediatamente em vez de ficar tentando de novo indefinidamente.

Em todos os três casos, o comportamento interativo normal (perguntar e esperar sua resposta num terminal de verdade) não muda em nada.


📂 Formato dos Arquivos Internos

Os arquivos .secrets.gpg e .mask.gpg são mantidos criptografados em disco usando a chave GPG definida no .gpg-id local. O formato em texto plano, antes da cifra, segue:

  • Formato de .secrets.gpg (associação 1:1 por caminho):

    <caminho-do-codinome-relativo-a-identidade> = <nome real / descrição>
    

    (Exemplo: a1/b2 = Servidor Produção - SSH)

  • Formato de .mask.gpg (associação N:N por alias/diretório):

    <alias> = <caminho-dir>
    

    (Exemplo: alias1@domain.com = servicos/financeiro)


🔒 Permissões e Segurança

  • O script audita o sistema de arquivos e exige permissão exatamente 600 nos arquivos de mapa criptografados (não aceita 640 nem qualquer outro valor).
  • O ciclo de vida dos arquivos temporários nas edições (edit e mask edit) é inteiramente gerenciado pela extensão, limpando o rastro com segurança (via shred/rm atrelado a um trap do shell) sem depender de plugins como o vim-gnupg.
  • O script recusa caminhos e blocos de geração de senhas que atravessam diretórios de identidades aninhadas, garantindo que arquivos nunca sejam cifrados pela chave de uma identidade indesejada.
  • Integração nativa com o Git do pass: todas as modificações nos mapas via script geram commits automáticos no repositório.
  • Todas as entradas do usuário passam por checagens de validação de path traversal (check_sneaky_paths) e sanitização de tokens.

🤝 Como Ajudar / Como Colaborar

Traduzindo ou corrigindo um idioma

Todas as mensagens do pass-secrets ficam em arquivos-fonte simples, um por idioma, na pasta i18n/ (pt.json, en.json, es.json, ru.json). São arquivos JSON comuns — não precisa saber bash nem entender o script pra traduzir.

Para corrigir uma tradução existente:

  1. Abra o .json do idioma em qualquer editor de texto.
  2. Edite o texto entre aspas da chave que quiser corrigir. Mantenha a mesma quantidade de %s que o original — são placeholders preenchidos em runtime (nome de identidade, caminho, etc.).
  3. Rode python3 tools/gen-i18n.py secrets.bash pra aplicar a mudança dentro do script.
  4. Rode bash -n secrets.bash pra conferir que a sintaxe continua válida.
  5. Abra um Pull Request.

Para adicionar um idioma novo que ainda não existe:

  1. Copie i18n/en.json para i18n/<código-do-idioma>.json (ex: i18n/fr.json para francês) como ponto de partida.
  2. Traduza os valores — não precisa ser tudo de uma vez. Qualquer chave que você deixar sem traduzir cai automaticamente para inglês (e depois para português) até alguém completar.
  3. Não esqueça da chave especial _usage_full — é o texto completo do --help naquele idioma. Use {PROG} no lugar de "pass secrets" (isso é substituído automaticamente em runtime).
  4. Rode python3 tools/gen-i18n.py secrets.bash — ele detecta o arquivo novo sozinho, não precisa editar mais nada.
  5. Teste com PASS_SECRETS_LANG=<código> pass secrets <identidade> ... e confira que as chaves traduzidas saem certas e as faltantes caem no fallback.
  6. Abra um Pull Request com o .json novo e o secrets.bash regenerado.

Nenhuma dessas etapas exige conhecimento de bash. tools/gen-i18n.py só precisa de Python 3 (nenhuma dependência externa) e é a única ferramenta necessária pra ir do .json traduzido até o secrets.bash final.

Você também pode usar o weblate para ajudar a traduzir.

Outras formas de contribuir

  • Relatar bugs e comportamentos inesperados — principalmente em contexto não-interativo (scripts, cron), fronteiras entre identidades aninhadas, e qualquer coisa que pareça um caso extremo não coberto.
  • Revisar segurança — todo o modelo de ameaça do projeto (isolamento por identidade, verificação de assinatura do .gpg-id, validação de path traversal) está aberto a escrutínio; um PR com prova prática de uma falha (não só teoria) é sempre bem-vindo.
  • Revisar traduções existentes — mesmo sem ser tradutor "oficial" de um idioma, sinalizar uma tradução estranha ou incorreta via issue já ajuda.

📄 Licença

Este projeto é disponibilizado sob a mesma licença do projeto password-store (GPLv2+).

About

pass-secrets é uma extensão leve para o password-store (pass) que obscurece a árvore de diretórios e nomes de serviços via mapeamentos GPG criptografados (.secrets.gpg e .mask.gpg). Garante isolamento estrito entre subdiretórios com chaves distintas, elimina dependências de superusuário e integra-se perfeitamente ao Git nativo do pass.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages