| 117 | }); |
| 118 | } |
| 119 | |
| 120 | // --- Sanitize sensitive information from error messages --- |
| 121 | function sanitizeErrorMessage(error: string, server?: ServerConfig): string { |
| 122 | let sanitized = error; |
| 123 | |
| 124 | // Remove passwords |
| 125 | sanitized = sanitized.replace(/sshpass -p '[^']*'/gi, "sshpass -p '***'"); |
| 126 | sanitized = sanitized.replace(/password[:\s]+\S+/gi, "password: ***"); |
| 127 | |
| 128 | // Mask IP addresses (full mask) |
| 129 | sanitized = sanitized.replace(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/g, '***.***.***.***'); |
| 130 | |
| 131 | // Mask IPv6 addresses (more aggressive) |
| 132 | sanitized = sanitized.replace(/([0-9a-fA-F]{1,4}:){2,}[0-9a-fA-F:.]+/g, '***:***:***:***'); |
| 133 | |
| 134 | // Remove SSH key paths |
| 135 | sanitized = sanitized.replace(/ssh -i [^\s]+/gi, "ssh -i ***"); |
| 136 | |
| 137 | // Remove usernames in connection strings |
| 138 | sanitized = sanitized.replace(/\b[a-zA-Z0-9_-]+@/g, "***@"); |
| 139 | |
| 140 | // If server config is provided, also remove specific server details |
| 141 | if (server) { |
| 142 | sanitized = sanitized.replace(new RegExp(server.host, 'g'), '***'); |
| 143 | sanitized = sanitized.replace(new RegExp(server.username, 'g'), '***'); |
| 144 | if (server.auth_method === 'password') { |
| 145 | try { |
| 146 | const password = decrypt(server.credentials); |
| 147 | sanitized = sanitized.replace(new RegExp(password, 'g'), '***'); |
| 148 | } catch (e) { |
| 149 | // Ignore decryption errors |
| 150 | } |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | return sanitized; |
| 155 | } |
| 156 | |