{
  "version": "https://jsonfeed.org/version/1",
  "title": "blog do Fabiano",
  "home_page_url": "https://eufabiano.site",
  "feed_url": "https://eufabiano.site/tag-open-source.json",
  "description": "Minhas notas da vida",
  "items": [
    {
      "id": "https://eufabiano.site/pass-gpg-e-um-backup-que-nao-depende-de-uma-maquina-so.html",
      "url": "https://eufabiano.site/pass-gpg-e-um-backup-que-nao-depende-de-uma-maquina-so.html",
      "title": "Pass, GPG e um backup que não depende de uma máquina só",
      "content_html": "<p data-sourcepos=\"3:1-3:226\">Hoje terminei uma parte importante da organização das minhas senhas: exportei uma cópia do meu cofre do KeePassXC e coloquei os dados no <a data-sourcepos=\"3:141-3:178\" href=\"https://www.passwordstore.org/\">pass</a>, o gerenciador de senhas simples do mundo Unix.</p>\n<p data-sourcepos=\"5:1-5:264\">O motivo principal não foi abandonar o KeePassXC imediatamente. Foi experimentar uma integração melhor com o terminal. Como eu já passo bastante tempo no shell, queria conseguir consultar senhas, copiar credenciais e gerar códigos OTP sem sair desse ambiente.</p>\n<p data-sourcepos=\"7:1-7:252\">Por enquanto vou manter os dois fluxos: o KeePassXC continua sendo a referência principal e o <code data-sourcepos=\"7:96-7:101\">pass</code> fica como uma segunda cópia em estudo. Ainda estou avaliando a melhor forma de sincronizar os dois cofres sem criar conflitos ou perder alterações.</p>\n<p data-sourcepos=\"9:1-9:158\">A ideia do <code data-sourcepos=\"9:12-9:17\">pass</code> é direta: cada entrada vira um arquivo de texto criptografado com GPG. O nome da entrada organiza o cofre e a senha fica na primeira linha.</p>\n<h2 id=\"a-saída-do-keepassxc\" data-sourcepos=\"11:1-11:24\">A saída do KeePassXC<a href=\"#a-saída-do-keepassxc\" aria-label=\"Link to heading 'A saída do KeePassXC'\" data-heading-content=\"A saída do KeePassXC\" class=\"anchor\"></a></h2>\n<p data-sourcepos=\"13:1-13:160\">O ponto de partida foi o meu cofre do KeePassXC. O KeePassXC permite exportar as entradas para CSV, então fiz essa exportação antes de começar a migração.</p>\n<p data-sourcepos=\"15:1-15:261\">O CSV é útil para transportar os dados, mas não é um formato adequado para deixar espalhado por aí: ele contém as senhas em texto puro. Por isso tratei o arquivo como uma etapa temporária e restrita, sem colocá-lo no Git, no servidor remoto ou na nuvem.</p>\n<p data-sourcepos=\"17:1-17:80\">Depois da exportação, criei uma versão sanitizada do arquivo. Nessa etapa eu:</p>\n<ul data-sourcepos=\"19:1-24:80\">\n<li data-sourcepos=\"19:1-19:49\">conferi as colunas e a quantidade de registros;</li>\n<li data-sourcepos=\"20:1-20:54\">preservei usuário, senha, URL, notas e tokens TOTP;</li>\n<li data-sourcepos=\"21:1-21:47\">normalizei os grupos para nomes mais simples;</li>\n<li data-sourcepos=\"22:1-22:37\">removi acentos dos identificadores;</li>\n<li data-sourcepos=\"23:1-23:40\">troquei espaços nos nomes por pontos;</li>\n<li data-sourcepos=\"24:1-24:80\">verifiquei títulos duplicados e caminhos que poderiam virar nomes inválidos.</li>\n</ul>\n<p data-sourcepos=\"26:1-26:29\">O arquivo intermediário foi:</p>\n<pre data-sourcepos=\"28:1-30:3\" class=\"marmite-code\"><code class=\"marmite-code-inner language-text\">~/caminho/para/senhas.sanitized.csv\n</code></pre>\n<p data-sourcepos=\"32:1-32:192\">Só depois dessa normalização o conteúdo foi importado para o <code data-sourcepos=\"32:66-32:71\">pass</code>. Ao final, o CSV continuou protegido com permissões restritas e não foi adicionado ao repositório de configurações.</p>\n<h2 id=\"do-csv-para-o-cofre\" data-sourcepos=\"34:1-34:22\">Do CSV para o cofre<a href=\"#do-csv-para-o-cofre\" aria-label=\"Link to heading 'Do CSV para o cofre'\" data-heading-content=\"Do CSV para o cofre\" class=\"anchor\"></a></h2>\n<p data-sourcepos=\"36:1-36:143\">Eu tinha um arquivo com minhas senhas em CSV. Ele tinha usuários, senhas, URLs, anotações e alguns tokens de autenticação em dois fatores.</p>\n<p data-sourcepos=\"38:1-38:142\">Antes de importar, organizei os nomes dos grupos. Em vez de caminhos longos como <code data-sourcepos=\"38:82-38:108\">meu cofre/família/pessoa</code>, passei a usar nomes mais curtos:</p>\n<pre data-sourcepos=\"40:1-45:3\" class=\"marmite-code\"><code class=\"marmite-code-inner language-text\">familia.pessoa\nfamilia.outro\nempresa.exemplo\nempresa.outro\n</code></pre>\n<p data-sourcepos=\"47:1-47:98\">Também substituí espaços nos nomes dos itens por pontos. Assim, uma entrada ficou parecida com:</p>\n<pre data-sourcepos=\"49:1-52:3\" class=\"marmite-code\"><code class=\"marmite-code-inner language-text\">empresa.exemplo/ambiente.de.stage\nfamilia.pessoa/banco.inter\n</code></pre>\n<p data-sourcepos=\"54:1-54:23\">O processo ficou assim:</p>\n<div class=\"mermaid-diagram\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1079.95\" height=\"75\" viewBox=\"0 0 1079.95 75\"><rect x=\"0\" y=\"0\" width=\"1079.95\" height=\"75\" fill=\"#FFFFFF\"/><defs><marker id=\"arrow-0\" viewBox=\"0 0 10 10\" refX=\"5\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"1\" stroke-dasharray=\"1,0\"/></marker><marker id=\"arrow-start-0\" viewBox=\"0 0 10 10\" refX=\"4.5\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\"><path d=\"M 0 5 L 10 10 L 10 0 z\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"1\" stroke-dasharray=\"1,0\"/></marker></defs><path id=\"edge-0\" class=\"edgePath\" data-edge-id=\"edge-0\" d=\"M 161.775,33.500 L 211.775,33.500\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"    stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(211.77 33.50) rotate(0.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><path id=\"edge-1\" class=\"edgePath\" data-edge-id=\"edge-1\" d=\"M 419.135,33.500 L 469.135,33.500\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"    stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(469.13 33.50) rotate(0.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><path id=\"edge-2\" class=\"edgePath\" data-edge-id=\"edge-2\" d=\"M 656.401,33.500 L 706.401,33.500\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"    stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(706.40 33.50) rotate(0.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><path id=\"edge-3\" class=\"edgePath\" data-edge-id=\"edge-3\" d=\"M 853.477,33.500 L 903.477,33.500\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"    stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(903.48 33.50) rotate(0.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><rect x=\"8.00\" y=\"8.00\" width=\"153.77\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"84.89\" y=\"37.00\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"84.89\" dy=\"0.00\">CSV sanitizado</tspan></text><rect x=\"706.40\" y=\"8.00\" width=\"147.08\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"779.94\" y=\"37.00\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"779.94\" dy=\"0.00\">Arquivos .gpg</tspan></text><rect x=\"469.13\" y=\"8.00\" width=\"187.27\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"562.77\" y=\"37.00\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"562.77\" dy=\"0.00\">Importação com pass</tspan></text><rect x=\"211.77\" y=\"8.00\" width=\"207.36\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"315.45\" y=\"37.00\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"315.45\" dy=\"0.00\">Normalização dos nomes</tspan></text><rect x=\"903.48\" y=\"8.00\" width=\"160.47\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"983.71\" y=\"37.00\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"983.71\" dy=\"0.00\">Vault de senhas</tspan></text></svg></div>\n<p data-sourcepos=\"64:1-64:164\">Foram importadas 223 entradas. Depois conferi se todas podiam ser descriptografadas e se as senhas estavam na primeira linha, que é o formato esperado pelo <code data-sourcepos=\"64:158-64:163\">pass</code>.</p>\n<h2 id=\"otp-sem-gambiarra\" data-sourcepos=\"66:1-66:20\">OTP sem gambiarra<a href=\"#otp-sem-gambiarra\" aria-label=\"Link to heading 'OTP sem gambiarra'\" data-heading-content=\"OTP sem gambiarra\" class=\"anchor\"></a></h2>\n<p data-sourcepos=\"68:1-68:132\">Também instalei a extensão <code data-sourcepos=\"68:30-68:39\">pass-otp</code>. Ela usa as URIs padrão <code data-sourcepos=\"68:66-68:77\">otpauth://</code> para gerar códigos de autenticação de dois fatores.</p>\n<p data-sourcepos=\"70:1-70:56\">Na primeira importação, eu tinha colocado a URI assim:</p>\n<pre data-sourcepos=\"72:1-74:3\" class=\"marmite-code\"><code class=\"marmite-code-inner language-text\">TOTP: otpauth://totp/...\n</code></pre>\n<p data-sourcepos=\"76:1-76:117\">Parecia organizado, mas a extensão não encontrava o token. O formato correto é deixar a URI em uma linha própria:</p>\n<pre data-sourcepos=\"78:1-80:3\" class=\"marmite-code\"><code class=\"marmite-code-inner language-text\">otpauth://totp/...\n</code></pre>\n<p data-sourcepos=\"82:1-82:145\">Depois de ajustar o CSV, zerei o cofre e importei tudo novamente. O resultado foi melhor: as entradas com OTP passaram a funcionar com o comando:</p>\n<pre data-sourcepos=\"84:1-86:3\" class=\"marmite-code\"><code class=\"marmite-code-inner language-bash\"><a-f>pass</a-f> otp <a-s>&quot;empresa.exemplo/servico.otp&quot;</a-s></code></pre>\n<p data-sourcepos=\"88:1-88:65\">Ou copiando o código diretamente para a área de transferência:</p>\n<pre data-sourcepos=\"90:1-92:3\" class=\"marmite-code\"><code class=\"marmite-code-inner language-bash\"><a-f>pass</a-f> otp <a-co>-c</a-co> <a-s>&quot;empresa.exemplo/servico.otp&quot;</a-s></code></pre>\n<h2 id=\"adicionando-novas-senhas\" data-sourcepos=\"94:1-94:27\">Adicionando novas senhas<a href=\"#adicionando-novas-senhas\" aria-label=\"Link to heading 'Adicionando novas senhas'\" data-heading-content=\"Adicionando novas senhas\" class=\"anchor\"></a></h2>\n<p data-sourcepos=\"96:1-96:47\">Para criar uma nova entrada, uso <code data-sourcepos=\"96:34-96:46\">pass insert</code>:</p>\n<pre class=\"marmite-code\" data-sourcepos=\"98:1-100:3\"><code class=\"marmite-code-inner language-bash\"><a-f>pass</a-f> insert empresa.exemplo/nova-senha</code></pre>\n<p data-sourcepos=\"102:1-102:149\">O <code data-sourcepos=\"102:3-102:8\">pass</code> pede a senha no terminal e salva o resultado criptografado. Para guardar também usuário, URL e outras informações, uso o modo multiline:</p>\n<pre class=\"marmite-code\" data-sourcepos=\"104:1-106:3\"><code class=\"marmite-code-inner language-bash\"><a-f>pass</a-f> insert <a-co>--multiline</a-co> empresa.exemplo/nova-senha</code></pre>\n<p data-sourcepos=\"108:1-108:21\">O formato fica assim:</p>\n<pre data-sourcepos=\"110:1-115:3\" class=\"marmite-code\"><code class=\"marmite-code-inner language-text\">minha-senha\nUsername: meu.usuario\nURL: https://servico.example\nNotes: alguma observação\n</code></pre>\n<p data-sourcepos=\"117:1-117:88\">A senha fica na primeira linha. Isso permite usar <code data-sourcepos=\"117:51-117:59\">pass -c</code> para copiar somente a senha:</p>\n<pre data-sourcepos=\"119:1-121:3\" class=\"marmite-code\"><code class=\"marmite-code-inner language-bash\"><a-f>pass</a-f> <a-co>-c</a-co> empresa.exemplo/nova-senha</code></pre>\n<h2 id=\"adicionando-novos-otps\" data-sourcepos=\"123:1-123:25\">Adicionando novos OTPs<a href=\"#adicionando-novos-otps\" aria-label=\"Link to heading 'Adicionando novos OTPs'\" data-heading-content=\"Adicionando novos OTPs\" class=\"anchor\"></a></h2>\n<p data-sourcepos=\"125:1-125:70\">Para adicionar um token de autenticação, uso a extensão <code data-sourcepos=\"125:60-125:69\">pass-otp</code>:</p>\n<pre class=\"marmite-code\" data-sourcepos=\"127:1-129:3\"><code class=\"marmite-code-inner language-bash\"><a-f>pass</a-f> otp insert empresa.exemplo/nova-senha</code></pre>\n<p data-sourcepos=\"131:1-131:127\">O comando pede uma URI no formato <code data-sourcepos=\"131:35-131:46\">otpauth://</code>. Normalmente ela vem do QR Code exibido pelo serviço ao ativar o segundo fator.</p>\n<p data-sourcepos=\"133:1-133:80\">Se eu já tenho uma entrada de senha e quero adicionar o OTP nela, uso <code data-sourcepos=\"133:72-133:79\">append</code>:</p>\n<pre class=\"marmite-code\" data-sourcepos=\"135:1-137:3\"><code class=\"marmite-code-inner language-bash\"><a-f>pass</a-f> otp append empresa.exemplo/nova-senha</code></pre>\n<p data-sourcepos=\"139:1-139:33\">Depois posso gerar o código com:</p>\n<pre data-sourcepos=\"141:1-143:3\" class=\"marmite-code\"><code class=\"marmite-code-inner language-bash\"><a-f>pass</a-f> otp empresa.exemplo/nova-senha</code></pre>\n<p data-sourcepos=\"145:1-145:44\">Ou copiá-lo para a área de transferência:</p>\n<pre data-sourcepos=\"147:1-149:3\" class=\"marmite-code\"><code class=\"marmite-code-inner language-bash\"><a-f>pass</a-f> otp <a-co>-c</a-co> empresa.exemplo/nova-senha</code></pre>\n<p data-sourcepos=\"151:1-151:110\">A URI do OTP é armazenada como uma linha própria dentro da entrada, começando diretamente com <code data-sourcepos=\"151:98-151:109\">otpauth://</code>.</p>\n<h2 id=\"o-cofre-também-é-um-repositório-git\" data-sourcepos=\"153:1-153:41\">O cofre também é um repositório Git<a href=\"#o-cofre-também-é-um-repositório-git\" aria-label=\"Link to heading 'O cofre também é um repositório Git'\" data-heading-content=\"O cofre também é um repositório Git\" class=\"anchor\"></a></h2>\n<p data-sourcepos=\"155:1-155:186\">Meu <code data-sourcepos=\"155:5-155:23\">~/.password-store</code> já era um repositório Git com um servidor remoto configurado. Isso significa que o <code data-sourcepos=\"155:110-155:115\">pass</code> consegue criar commits quando uma entrada é adicionada ou atualizada.</p>\n<p data-sourcepos=\"157:1-157:192\">Depois da reorganização, os nomes antigos foram removidos e as entradas novas ficaram nos grupos <code data-sourcepos=\"157:100-157:110\">empresa.*</code> e <code data-sourcepos=\"157:114-157:124\">familia.*</code>. Fiz a consolidação em um commit e enviei para o servidor remoto.</p>\n<p data-sourcepos=\"159:1-159:20\">O fluxo ficou assim:</p>\n<div class=\"mermaid-diagram\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"334.18115\" height=\"477.07648\" viewBox=\"0 0 334.18115 477.07648\"><rect x=\"0\" y=\"0\" width=\"334.18115\" height=\"477.07648\" fill=\"#FFFFFF\"/><defs><marker id=\"arrow-0\" viewBox=\"0 0 10 10\" refX=\"5\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"1\" stroke-dasharray=\"1,0\"/></marker><marker id=\"arrow-start-0\" viewBox=\"0 0 10 10\" refX=\"4.5\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\"><path d=\"M 0 5 L 10 10 L 10 0 z\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"1\" stroke-dasharray=\"1,0\"/></marker></defs><path id=\"edge-0\" class=\"edgePath\" data-edge-id=\"edge-0\" d=\"M 255.381,59.000 L 255.381,68.532 Q 255.381,76.332 248.948,80.740 L 240.135,86.779 Q 233.701,91.187 233.701,98.987 L 233.701,108.519\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"    stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(233.70 108.52) rotate(90.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><path id=\"edge-1\" class=\"edgePath\" data-edge-id=\"edge-1\" d=\"M 198.293,159.519 L 198.293,209.038\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"    stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(198.29 209.04) rotate(90.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><path id=\"edge-2\" class=\"edgePath\" data-edge-id=\"edge-2\" d=\"M 198.284,260.038 L 198.284,309.557\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"    stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(198.28 309.56) rotate(90.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><path id=\"edge-3\" class=\"edgePath\" data-edge-id=\"edge-3\" d=\"M 198.278,360.557 L 198.278,410.076\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"    stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(198.28 410.08) rotate(90.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><path id=\"edge-4\" class=\"edgePath\" data-edge-id=\"edge-4\" d=\"M 181.869,33.500 L 231.388,33.500\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"   stroke-dasharray=\"4 4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(231.39 33.50) rotate(0.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><rect x=\"111.34\" y=\"410.08\" width=\"173.87\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"198.28\" y=\"439.08\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"198.28\" dy=\"0.00\">Backup versionado</tspan></text><rect x=\"104.65\" y=\"309.56\" width=\"187.27\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"198.28\" y=\"338.56\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"198.28\" dy=\"0.00\">Servidor Git remoto</tspan></text><rect x=\"128.11\" y=\"108.52\" width=\"140.38\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"198.30\" y=\"137.52\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"198.30\" dy=\"0.00\">Entrada .gpg</tspan></text><rect x=\"138.15\" y=\"209.04\" width=\"120.28\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"198.29\" y=\"238.04\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"198.29\" dy=\"0.00\">Git local</tspan></text><rect x=\"8.00\" y=\"8.00\" width=\"173.87\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"94.93\" y=\"37.00\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"94.93\" dy=\"0.00\">Chave GPG privada</tspan></text><rect x=\"231.39\" y=\"8.00\" width=\"86.79\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"274.78\" y=\"37.00\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"274.78\" dy=\"0.00\">pass</tspan></text></svg></div>\n<p data-sourcepos=\"171:1-171:191\">O servidor remoto recebe somente os arquivos criptografados. Mesmo assim, o repositório não substitui o backup da chave GPG. Sem a chave privada, os arquivos <code data-sourcepos=\"171:161-171:166\">.gpg</code> continuam inacessíveis.</p>\n<h2 id=\"o-problema-da-máquina-única\" data-sourcepos=\"173:1-173:32\">O problema da máquina única<a href=\"#o-problema-da-máquina-única\" aria-label=\"Link to heading 'O problema da máquina única'\" data-heading-content=\"O problema da máquina única\" class=\"anchor\"></a></h2>\n<p data-sourcepos=\"175:1-175:65\">Foi aí que veio a próxima pergunta: e se esta máquina quebrar?</p>\n<p data-sourcepos=\"177:1-177:142\">A chave GPG não deve ficar somente em um computador. Também não é uma boa ideia colocar uma cópia sem proteção em um serviço de nuvem.</p>\n<p data-sourcepos=\"179:1-179:113\">Em vez de copiar todo o <code data-sourcepos=\"179:25-179:34\">~/.gnupg</code>, preparei um script genérico no meu repositório de configurações pessoais:</p>\n<pre class=\"marmite-code\" data-sourcepos=\"181:1-183:3\"><code class=\"marmite-code-inner language-text\">scripts/backup-gnupg.sh\n</code></pre>\n<p data-sourcepos=\"185:1-185:67\">O script exporta somente o que importa para recuperar a identidade:</p>\n<ul data-sourcepos=\"187:1-192:33\">\n<li data-sourcepos=\"187:1-187:17\">chave pública;</li>\n<li data-sourcepos=\"188:1-188:16\">chave privada;</li>\n<li data-sourcepos=\"189:1-189:21\">subchaves privadas;</li>\n<li data-sourcepos=\"190:1-190:15\"><code data-sourcepos=\"190:3-190:14\">ownertrust</code>;</li>\n<li data-sourcepos=\"191:1-191:30\">certificados de revogação;</li>\n<li data-sourcepos=\"192:1-192:33\">configurações GPG existentes.</li>\n</ul>\n<p data-sourcepos=\"194:1-194:77\">Ele não copia sockets, cache, locks nem arquivos temporários do agente GPG.</p>\n<p data-sourcepos=\"196:1-196:69\">O resultado é um arquivo 7-Zip criptografado com uma senha própria:</p>\n<div class=\"mermaid-diagram\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"903.6201\" height=\"176\" viewBox=\"0 0 903.6201 176\"><rect x=\"0\" y=\"0\" width=\"903.6201\" height=\"176\" fill=\"#FFFFFF\"/><defs><marker id=\"arrow-0\" viewBox=\"0 0 10 10\" refX=\"5\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"1\" stroke-dasharray=\"1,0\"/></marker><marker id=\"arrow-start-0\" viewBox=\"0 0 10 10\" refX=\"4.5\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\"><path d=\"M 0 5 L 10 10 L 10 0 z\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"1\" stroke-dasharray=\"1,0\"/></marker></defs><path id=\"edge-0\" class=\"edgePath\" data-edge-id=\"edge-0\" d=\"M 135.634,84.000 L 185.634,84.000\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"    stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(185.63 84.00) rotate(0.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><path id=\"edge-1\" class=\"edgePath\" data-edge-id=\"edge-1\" d=\"M 372.900,84.000 L 422.900,84.000\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"    stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(422.90 84.00) rotate(0.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><path id=\"edge-2\" class=\"edgePath\" data-edge-id=\"edge-2\" d=\"M 643.656,60.171 L 654.336,60.171 Q 661.156,60.171 667.906,59.194 L 669.406,58.977 Q 676.156,58.000 682.977,58.000 L 693.656,58.000\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"    stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(693.66 58.00) rotate(0.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><path id=\"edge-3\" class=\"edgePath\" data-edge-id=\"edge-3\" d=\"M 643.656,108.500 L 654.373,108.500 Q 661.156,108.500 667.906,109.175 L 669.406,109.325 Q 676.156,110.000 682.940,110.000 L 693.656,110.000\" fill=\"none\" stroke=\"#64748B\" stroke-width=\"2\"    stroke-linecap=\"round\" stroke-linejoin=\"round\" /><g transform=\"translate(693.66 110.00) rotate(0.00)\"><polygon points=\"0,0 -7.50,3.90 -7.50,-3.90\" fill=\"#64748B\" stroke=\"#64748B\" stroke-width=\"2\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/></g><rect x=\"8.00\" y=\"58.50\" width=\"127.63\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"71.82\" y=\"87.50\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"71.82\" dy=\"0.00\">Chaves GPG</tspan></text><rect x=\"693.66\" y=\"109.00\" width=\"193.96\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"790.64\" y=\"138.00\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"790.64\" dy=\"0.00\">Mídia física offline</tspan></text><rect x=\"693.66\" y=\"8.00\" width=\"147.08\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"767.19\" y=\"37.00\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"767.19\" dy=\"0.00\">Nuvem pessoal</tspan></text><rect x=\"185.63\" y=\"58.50\" width=\"187.27\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"279.27\" y=\"87.50\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"279.27\" dy=\"0.00\">Exportação seletiva</tspan></text><rect x=\"422.90\" y=\"58.50\" width=\"220.76\" height=\"51.00\" rx=\"3\" ry=\"3\" fill=\"#F8FAFC\" stroke=\"#94A3B8\" stroke-width=\"1\" stroke-linejoin=\"round\" stroke-linecap=\"round\"/><text x=\"533.28\" y=\"87.50\" text-anchor=\"middle\" font-family=\"Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,DejaVu Sans,Liberation Sans,sans-serif,Noto Color Emoji,Apple Color Emoji,Segoe UI Emoji\" font-size=\"14\" fill=\"#0F172A\"><tspan x=\"533.28\" dy=\"0.00\">Arquivo 7z criptografado</tspan></text></svg></div>\n<p data-sourcepos=\"206:1-206:124\">A senha do arquivo 7-Zip é diferente da senha da chave GPG. Isso é importante: são duas camadas diferentes de proteção.</p>\n<h2 id=\"o-que-ficou-versionado\" data-sourcepos=\"208:1-208:25\">O que ficou versionado<a href=\"#o-que-ficou-versionado\" aria-label=\"Link to heading 'O que ficou versionado'\" data-heading-content=\"O que ficou versionado\" class=\"anchor\"></a></h2>\n<p data-sourcepos=\"210:1-210:130\">O repositório <code data-sourcepos=\"210:16-210:25\">dotfiles</code> é o lugar das minhas configurações pessoais e dos pequenos scripts que ajudam a recuperar o ambiente.</p>\n<p data-sourcepos=\"212:1-212:237\">Para este setup, versionei o script genérico de backup seletivo do GPG e sua documentação. O backup criado não foi colocado no repositório. O Git guarda o script que sabe criar o backup, não o arquivo com as minhas chaves privadas.</p>\n<h2 id=\"fechando-o-dia\" data-sourcepos=\"214:1-214:17\">Fechando o dia<a href=\"#fechando-o-dia\" aria-label=\"Link to heading 'Fechando o dia'\" data-heading-content=\"Fechando o dia\" class=\"anchor\"></a></h2>\n<p data-sourcepos=\"216:1-216:194\">O mais importante de hoje não foi somente trocar um gerenciador de senhas. Foi experimentar um fluxo mais próximo do terminal sem abandonar o KeePassXC antes de entender bem a sincronização.</p>\n<p data-sourcepos=\"218:1-218:96\">Por enquanto, os dois cofres convivem. Foi uma migração controlada, não uma troca definitiva.</p>\n<p data-sourcepos=\"220:1-220:42\">Também consegui separar melhor as coisas:</p>\n<ul data-sourcepos=\"222:1-228:59\">\n<li data-sourcepos=\"222:1-222:50\">o KeePassXC continua como referência principal;</li>\n<li data-sourcepos=\"223:1-223:70\">o <code data-sourcepos=\"223:5-223:10\">pass</code> guarda uma cópia criptografada e acessível pelo terminal;</li>\n<li data-sourcepos=\"224:1-224:30\">o Git registra as mudanças;</li>\n<li data-sourcepos=\"225:1-225:66\">o servidor remoto guarda uma cópia dos arquivos criptografados;</li>\n<li data-sourcepos=\"226:1-226:40\">o GPG protege e recupera a identidade;</li>\n<li data-sourcepos=\"227:1-227:69\">a nuvem pessoal e a mídia física guardam um backup criptografado;</li>\n<li data-sourcepos=\"228:1-228:59\">o repositório <code data-sourcepos=\"228:18-228:27\">dotfiles</code> documenta como refazer o setup.</li>\n</ul>\n<p data-sourcepos=\"230:1-230:157\">Ainda quero testar a restauração completa em uma máquina virtual. Backup bom não é o que existe. É o que foi restaurado com sucesso pelo menos uma vez.</p>\n",
      "summary": "",
      "date_published": "2026-09-08T00:00:00-00:00",
      "image": "",
      "authors": [],
      "tags": [
        "tech",
        "vida",
        "open-source"
      ],
      "language": "pt-br"
    }
  ]
}