UNPKG

@codecot/pw-checker

Version:

A comprehensive CLI tool to audit passwords locally using HIBP and import from Chrome/Bitwarden

96 lines 3.85 kB
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