@codecot/pw-checker
Version:
A comprehensive CLI tool to audit passwords locally using HIBP and import from Chrome/Bitwarden
96 lines • 3.85 kB
JavaScript
import fs from "fs";
import path from "path";
import csv from "csv-parser";
import { fileURLToPath } from "url";
import sqlite3 from "sqlite3";
import { open } from "sqlite";
import chalk from "chalk";
// ESM replacement for __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const dbPath = path.resolve(__dirname, "../db/pw_entries.sqlite");
/**
* Import passwords from a Chrome exported CSV file
* @param csvPath Path to the CSV file exported from Chrome
* @returns Number of imported entries
*/
export async function importFromChromeCsv(csvPath) {
if (!fs.existsSync(csvPath)) {
console.error(chalk.red(`❌ File not found: ${csvPath}`));
return 0;
}
try {
const db = await open({
filename: dbPath,
driver: sqlite3.Database,
});
let importCount = 0;
const results = [];
// Process the CSV file
await new Promise((resolve, reject) => {
fs.createReadStream(csvPath)
.pipe(csv())
.on("data", (data) => {
// Chrome's exported CSV has 'name', 'url', 'username', 'password' columns
// The 'name' might be different or not exist in some exports, so we handle both cases
const url = data.url || data.origin_url || "";
const username = data.username || data.username_value || "";
const password = data.password || data.password_value || "";
const name = data.name || getDomainFromUrl(url);
const compromised = data.compromised_type === "Compromised" ? 1 : 0;
if (url && username && password) {
results.push({
name,
url,
username,
password,
compromised,
});
}
})
.on("end", () => {
resolve();
})
.on("error", (error) => {
reject(error);
});
});
console.log(chalk.blue(`📊 Found ${results.length} entries in Chrome CSV`));
// Import the data into the database
for (const row of results) {
const existingEntry = await db.get("SELECT id, password FROM pw_entries WHERE url = ? AND username = ?", row.url, row.username);
if (existingEntry) {
// If entry exists but has no password (from Chrome DB import), update it
if (existingEntry.password === null) {
await db.run("UPDATE pw_entries SET password = ?, notes = ? WHERE id = ?", row.password, "Updated with password from Chrome CSV export", existingEntry.id);
importCount++;
console.log(chalk.green(`✅ Updated existing entry for ${row.username} at ${getDomainFromUrl(row.url)} with password`));
}
continue;
}
// Insert new entry
await db.run("INSERT INTO pw_entries (name, url, username, password, compromised, source) VALUES (?, ?, ?, ?, ?, 'chrome')", row.name, row.url, row.username, row.password, row.compromised);
importCount++;
}
await db.close();
return importCount;
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(chalk.red(`❌ Error importing from Chrome CSV: ${errorMessage}`));
return 0;
}
}
/**
* Extract domain name from URL
*/
function getDomainFromUrl(url) {
try {
const domain = new URL(url).hostname;
return domain;
}
catch (e) {
return url;
}
}
//# sourceMappingURL=importFromChromeCsv.js.map