import fs from 'node:fs'; import path from 'node:path'; export async function listKeys(sshDir, vaultDir, tmpDir) { console.log('\nšŸ“‚ Checking keys in:'); console.log(` SSH: ${sshDir}`); console.log(` Vault: ${vaultDir}`); console.log(` Tmp: ${tmpDir}\n`); const keyMap = new Map(); // Scan SSH directory if (fs.existsSync(sshDir)) { const sshFiles = fs.readdirSync(sshDir).filter((file) => file.startsWith('id_')); for (const file of sshFiles) { const keyName = file.replace(/\.pub$/, ''); const isPub = file.endsWith('.pub'); if (!keyMap.has(keyName)) { keyMap.set(keyName, { name: keyName, inSsh: !isPub, hasSshPub: isPub, inVault: false, inTmp: false, hasTmpPub: false, }); } else { const key = keyMap.get(keyName); if (isPub) { key.hasSshPub = true; } else { key.inSsh = true; } } } } // Scan tmp directory if (fs.existsSync(tmpDir)) { const tmpFiles = fs.readdirSync(tmpDir).filter((file) => file.startsWith('id_')); for (const file of tmpFiles) { const keyName = file.replace(/\.pub$/, ''); const isPub = file.endsWith('.pub'); if (!keyMap.has(keyName)) { keyMap.set(keyName, { name: keyName, inSsh: false, hasSshPub: false, inVault: false, inTmp: !isPub, hasTmpPub: isPub, }); } else { const key = keyMap.get(keyName); if (isPub) { key.hasTmpPub = true; } else { key.inTmp = true; } } } } // Scan vault directory if (fs.existsSync(vaultDir)) { const vaultDirs = fs.readdirSync(vaultDir).filter((dir) => { const stat = fs.statSync(path.join(vaultDir, dir)); return stat.isDirectory(); }); for (const dir of vaultDirs) { const keyName = `id_${dir}`; const encryptedPath = path.join(vaultDir, dir, `${keyName}.age`); if (fs.existsSync(encryptedPath)) { if (!keyMap.has(keyName)) { keyMap.set(keyName, { name: keyName, inSsh: false, hasSshPub: false, inVault: true, inTmp: false, hasTmpPub: false, }); } else { keyMap.get(keyName).inVault = true; } } } } // Display results if (keyMap.size === 0) { console.log('āš ļø No SSH keys found.\n'); return; } console.log('šŸ”‘ SSH Keys:\n'); console.log(' Key Name [Vault] [Tmp] [.ssh]'); console.log(` ${'─'.repeat(58)}`); const sortedKeys = Array.from(keyMap.values()).sort((a, b) => a.name.localeCompare(b.name)); for (const key of sortedKeys) { const vaultMark = key.inVault ? 'āœ“' : ' '; const tmpMark = key.inTmp ? 'āœ“' : ' '; const sshMark = key.inSsh ? 'āœ“' : ' '; // Show (.pub) if present in any location const hasPub = key.hasSshPub || key.hasTmpPub; const pubIndicator = hasPub ? ' (.pub)' : ''; // Determine status const status = key.inVault && key.inSsh ? 'āœ…' : key.inVault && key.inTmp ? 'šŸ”“' : key.inVault ? 'šŸ”’' : 'āš ļø '; const namePart = `${key.name}${pubIndicator}`.padEnd(32); console.log(` ${status} ${namePart} [${vaultMark}] [${tmpMark}] [${sshMark}]`); } console.log('\n Legend:'); console.log(' āœ… = Managed (encrypted in vault + active in .ssh)'); console.log(' šŸ”“ = Decrypted (in vault + decrypted to tmp)'); console.log(' šŸ”’ = Encrypted only (in vault, not decrypted)'); console.log(' āš ļø = Unmanaged (in .ssh or tmp, not encrypted in vault)\n'); }