@hashangit/breachhound
Version:
An efficient OSINT tool for uncovering digital footprints associated with a username. TypeScript port of GoSearch.
239 lines • 11.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.VERSION = exports.ASCII_ART = void 0;
exports.printHeader = printHeader;
exports.appendToFile = appendToFile;
exports.deleteOldFile = deleteOldFile;
exports.displayResults = displayResults;
const chalk_1 = __importDefault(require("chalk"));
const fs = __importStar(require("fs/promises"));
exports.ASCII_ART = `...`; // Your ASCII art
exports.VERSION = '1.0.0'; // Keep version consistent or read from package.json
function printHeader(username, siteCount, options) {
console.clear();
console.log(chalk_1.default.blue(exports.ASCII_ART));
console.log(`BreachHound ${exports.VERSION} - TypeScript Port`);
console.log(chalk_1.default.grey('⎯'.repeat(60)));
console.log(`:: Target Username : ${chalk_1.default.cyan(username)}`);
console.log(`:: Websites to Check : ${siteCount}`);
if (options.hideFalsePositives)
console.log(`:: Hide Uncertain : ${chalk_1.default.yellow('Yes')}`);
if (options.breachDirectoryEnabled)
console.log(`:: BreachDirectory : ${chalk_1.default.green('Enabled')}`);
console.log(chalk_1.default.grey('⎯'.repeat(60)));
if (!options.hideFalsePositives) {
console.log(chalk_1.default.yellow('[!] Yellow [?] links indicate uncertainty about the profile\'s existence.\n'));
}
}
async function appendToFile(targetUsername, content) {
// ... (implementation as before) ...
const filePath = `${targetUsername}.txt`;
try {
await fs.appendFile(filePath, content + '\n', 'utf8');
}
catch (error) {
console.error(chalk_1.default.red(`[-] Error writing to file ${filePath}: ${error}`));
}
}
async function deleteOldFile(targetUsername) {
// ... (implementation as before) ...
const filePath = `${targetUsername}.txt`;
try {
await fs.unlink(filePath);
// console.log(chalk.grey(`[*] Deleted old results file: ${filePath}`)); // Optional: log deletion
}
catch (error) {
if (error.code !== 'ENOENT') { // Ignore error if file doesn't exist
console.error(chalk_1.default.red(`[-] Error deleting old results file ${filePath}: ${error}`));
}
}
}
async function displayResults(results, username, hideFalsePositives) {
// --- Website Results ---
console.log(chalk_1.default.yellow(`\n[*] Website Scan Results:`));
results.websiteResults.forEach(res => {
if (res.status === 'found') {
const line = `[+] ${res.siteName}: ${res.profileUrl}`;
console.log(chalk_1.default.green(line));
appendToFile(username, line);
}
else if (res.status === 'uncertain' && !hideFalsePositives) {
const line = `[?] ${res.siteName}: ${res.profileUrl}`;
console.log(chalk_1.default.yellow(line));
appendToFile(username, `[?] ${line}`); // Add prefix to file too
}
else if (res.status === 'error') {
// Optional: log errors verbosely if needed
// console.error(chalk.red(`[-] Error checking ${res.siteName}: ${res.error}`));
}
});
// --- API Results ---
await displayApiResult(results.hudsonRockResult, username);
await displayApiResult(results.breachDirectoryResult, username);
await displayApiResult(results.proxyNovaResult, username);
await displayApiResult(results.domainCheckResult, username);
// --- Summary ---
console.log(chalk_1.default.grey('⎯'.repeat(60)));
const summaryLines = [
`:: Profiles Found / Uncertain : ${results.summary.profilesFound}`,
`:: Total Time Taken : ${results.summary.durationSeconds} seconds`,
`:: Report saved to : ${username}.txt`
];
summaryLines.forEach(line => console.log(line));
await appendToFile(username, '\n' + chalk_1.default.grey('⎯'.repeat(60)) + '\n' + summaryLines.join('\n'));
console.log(chalk_1.default.grey('⎯'.repeat(60)));
}
// Helper to display formatted API results
async function displayApiResult(result, username) {
console.log(chalk_1.default.grey('⎯'.repeat(60)));
console.log(chalk_1.default.yellow(`[*] ${result.service} Results:`));
if (result.status === 'skipped') {
const msg = `:: ${result.service} check skipped (API key may be missing).`;
console.log(chalk_1.default.grey(msg));
await appendToFile(username, `\n--- ${result.service} Check ---`);
await appendToFile(username, msg);
return;
}
await appendToFile(username, `\n--- ${result.service} Check ---`);
if (result.status === 'error') {
const msg = `:: Error querying ${result.service}: ${result.error}`;
console.error(chalk_1.default.red(msg));
await appendToFile(username, msg);
return;
}
// Add specific formatting based on result.service and result.details
// Example for HudsonRock:
if (result.service === 'HudsonRock') {
const data = result.details; // Use any for now, define specific type later
if (result.found && data?.stealers) {
// ... (detailed printing logic for stealers as before) ...
const msg = ":: This username is associated with a computer infected by an info-stealer.";
console.log(chalk_1.default.red(msg));
await appendToFile(username, msg);
// ... loop through stealers, print details ...
}
else {
const msg = ":: This username is not associated with a computer infected by an info-stealer.";
console.log(chalk_1.default.green(msg));
await appendToFile(username, msg);
}
}
// Formatting for BreachDirectory:
else if (result.service === 'BreachDirectory') {
if (result.found && result.details?.breaches?.length > 0) {
const count = result.details.foundCount || result.details.breaches.length;
const msg = `[+] Found ${count} breach entries:`;
console.log(chalk_1.default.green(msg));
await appendToFile(username, msg);
// Loop through breach entries and print details
for (const entry of result.details.breaches) {
let passMsg = '';
if (entry.crackedPassword) {
passMsg = `[+] Password (Cracked): ${entry.crackedPassword}`;
}
else if (entry.password) {
passMsg = `[+] Password: ${entry.password}`;
}
else {
passMsg = `[?] Password: Not Available`;
}
console.log(chalk_1.default.green(passMsg));
await appendToFile(username, passMsg);
if (entry.email) {
const emailMsg = `[+] Email: ${entry.email}`;
console.log(chalk_1.default.green(emailMsg));
await appendToFile(username, emailMsg);
}
if (entry.hash) {
const hashMsg = `[+] Hash: ${entry.hash}`;
console.log(chalk_1.default.grey(hashMsg)); // Use grey for hash
await appendToFile(username, hashMsg);
}
if (entry.sha1) {
const sha1Msg = `[+] SHA1: ${entry.sha1}`;
console.log(chalk_1.default.grey(sha1Msg)); // Use grey for hash
await appendToFile(username, sha1Msg);
}
if (entry.source) {
const sourceMsg = `[+] Source: ${entry.source}`;
console.log(chalk_1.default.green(sourceMsg));
await appendToFile(username, sourceMsg);
}
console.log(''); // Add a blank line between entries
await appendToFile(username, '');
}
}
else {
const msg = `[-] No breaches found.`;
console.log(chalk_1.default.red(msg)); // Use red for "not found"
await appendToFile(username, msg);
}
}
// Formatting for ProxyNova
else if (result.service === 'ProxyNova') {
if (result.found && result.details) {
// Assuming details contains info like count or entries
const count = result.details.found || (Array.isArray(result.details.entries) ? result.details.entries.length : 0);
const msg = `[+] Found ${count} potential credential leak(s) in Comb DB.`;
console.log(chalk_1.default.green(msg));
await appendToFile(username, msg);
// Optionally loop through result.details.entries if they exist and print them
}
else {
const msg = `[-] No potential credential leaks found in Comb DB.`;
console.log(chalk_1.default.red(msg));
await appendToFile(username, msg);
}
}
// Formatting for DomainCheck
else if (result.service === 'DomainCheck') {
if (result.found && result.details?.found?.length > 0) {
const foundDomains = result.details.found.join(', ');
const msg = `[+] Found potentially available domains: ${foundDomains}`;
console.log(chalk_1.default.green(msg));
await appendToFile(username, msg);
}
else {
const msg = `[-] No potentially available domains found matching the username.`;
console.log(chalk_1.default.red(msg));
await appendToFile(username, msg);
}
}
}
//# sourceMappingURL=ui.js.map