chrome-cookie-extractor
Version:
Extract and decrypt Chrome cookies with curl integration - includes auth-curl command for authenticated requests
262 lines • 11.5 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 (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChromeCookieExtractor = void 0;
const sqlite3 = __importStar(require("sqlite3"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const profile_detector_1 = require("./profile-detector");
const decryptor_1 = require("./decryptor");
class ChromeCookieExtractor {
constructor() {
this.profiles = profile_detector_1.ProfileDetector.detectAllProfiles();
}
getProfiles() {
return this.profiles;
}
async extractCookies(options = {}) {
if (this.profiles.length === 0) {
throw new Error('No Chrome/Brave profiles found');
}
const allCookies = [];
const { domain, profiles: requestedProfiles } = options;
const profilesToProcess = requestedProfiles
? this.profiles.filter(p => requestedProfiles.includes(p.name))
: this.profiles;
for (const profile of profilesToProcess) {
try {
const cookies = await this.extractFromDatabase(profile.cookiesPath, domain);
allCookies.push(...cookies);
}
catch (error) {
console.error(`Warning: Failed to extract cookies from ${profile.name}:`, error);
}
}
return allCookies;
}
async extractFromDatabase(cookiesPath, domain) {
return new Promise((resolve, reject) => {
// Try direct access first without copying
const db = new sqlite3.Database(cookiesPath, sqlite3.OPEN_READONLY, (err) => {
if (err) {
// If direct access fails, try the copy method
this.extractFromDatabaseWithCopy(cookiesPath, domain)
.then(resolve)
.catch(reject);
return;
}
// Set busy timeout to handle locks
db.run('PRAGMA busy_timeout = 30000', (err) => {
if (err) {
console.warn('Could not set busy timeout:', err);
}
});
// Check table structure
db.all('PRAGMA table_info(cookies)', (err, rows) => {
if (err) {
db.close();
reject(err);
return;
}
const columns = rows.map(row => row.name);
const hasEncryptedValue = columns.includes('encrypted_value');
let query;
let params = [];
if (hasEncryptedValue) {
query = `
SELECT name, value, encrypted_value, host_key, path, expires_utc,
is_secure, is_httponly, creation_utc
FROM cookies
`;
}
else {
query = `
SELECT name, value, host_key, path, expires_utc,
is_secure, is_httponly, creation_utc
FROM cookies
`;
}
if (domain) {
query += ' WHERE host_key LIKE ?';
params.push(`%${domain}%`);
}
db.all(query, params, (err, rows) => {
if (err) {
db.close();
reject(err);
return;
}
const cookies = [];
for (const row of rows) {
let finalValue;
if (hasEncryptedValue && row.encrypted_value) {
// Try to decrypt the encrypted value
const decryptedValue = decryptor_1.CookieDecryptor.decryptValue(row.encrypted_value);
finalValue = decryptedValue !== '[ENCRYPTED]' ? decryptedValue : row.value || '[ENCRYPTED]';
}
else {
finalValue = row.value || '';
}
cookies.push({
name: row.name,
value: finalValue,
domain: row.host_key,
path: row.path,
expires: row.expires_utc,
secure: Boolean(row.is_secure),
httponly: Boolean(row.is_httponly),
creationTime: row.creation_utc
});
}
db.close();
resolve(cookies);
});
});
});
});
}
async extractFromDatabaseWithCopy(cookiesPath, domain) {
// Create temporary copy to avoid database lock issues
const tempDir = os.tmpdir();
const tempCookiesPath = path.join(tempDir, `cookies_${Date.now()}_${Math.random().toString(36).slice(2)}.db`);
try {
fs.copyFileSync(cookiesPath, tempCookiesPath);
return new Promise((resolve, reject) => {
const db = new sqlite3.Database(tempCookiesPath, sqlite3.OPEN_READONLY, (err) => {
if (err) {
reject(err);
return;
}
// Check table structure
db.all('PRAGMA table_info(cookies)', (err, rows) => {
if (err) {
db.close();
reject(err);
return;
}
const columns = rows.map(row => row.name);
const hasEncryptedValue = columns.includes('encrypted_value');
let query;
let params = [];
if (hasEncryptedValue) {
query = `
SELECT name, value, encrypted_value, host_key, path, expires_utc,
is_secure, is_httponly, creation_utc
FROM cookies
`;
}
else {
query = `
SELECT name, value, host_key, path, expires_utc,
is_secure, is_httponly, creation_utc
FROM cookies
`;
}
if (domain) {
query += ' WHERE host_key LIKE ?';
params.push(`%${domain}%`);
}
db.all(query, params, (err, rows) => {
if (err) {
db.close();
reject(err);
return;
}
const cookies = [];
for (const row of rows) {
let finalValue;
if (hasEncryptedValue && row.encrypted_value) {
// Try to decrypt the encrypted value
const decryptedValue = decryptor_1.CookieDecryptor.decryptValue(row.encrypted_value);
finalValue = decryptedValue !== '[ENCRYPTED]' ? decryptedValue : row.value || '[ENCRYPTED]';
}
else {
finalValue = row.value || '';
}
cookies.push({
name: row.name,
value: finalValue,
domain: row.host_key,
path: row.path,
expires: row.expires_utc,
secure: Boolean(row.is_secure),
httponly: Boolean(row.is_httponly),
creationTime: row.creation_utc
});
}
db.close();
resolve(cookies);
});
});
});
});
}
finally {
// Clean up temporary file
if (fs.existsSync(tempCookiesPath)) {
fs.unlinkSync(tempCookiesPath);
}
}
}
formatAsNetscape(cookies) {
const lines = ['# Netscape HTTP Cookie File'];
for (const cookie of cookies) {
// Skip encrypted cookies
if (cookie.value === '[ENCRYPTED]') {
continue;
}
// Convert Chrome's expires_utc (Windows FILETIME) to Unix timestamp
const expires = cookie.expires > 0
? Math.floor((cookie.expires - 11644473600000000) / 1000000)
: 0;
const domain = cookie.domain;
const domainFlag = domain.startsWith('.') ? 'TRUE' : 'FALSE';
const path = cookie.path;
const secure = cookie.secure ? 'TRUE' : 'FALSE';
const name = cookie.name;
const value = cookie.value;
lines.push(`${domain}\t${domainFlag}\t${path}\t${secure}\t${expires}\t${name}\t${value}`);
}
return lines.join('\n');
}
formatAsCurl(cookies) {
const validCookies = cookies.filter(c => c.value !== '[ENCRYPTED]');
if (validCookies.length === 0) {
return '';
}
const cookiePairs = validCookies.map(c => `${c.name}=${c.value}`);
return `-H "Cookie: ${cookiePairs.join('; ')}"`;
}
formatAsJson(cookies) {
return JSON.stringify(cookies, null, 2);
}
async saveCookiesFile(cookies, outputPath) {
const netscapeFormat = this.formatAsNetscape(cookies);
fs.writeFileSync(outputPath, netscapeFormat, 'utf8');
}
}
exports.ChromeCookieExtractor = ChromeCookieExtractor;
//# sourceMappingURL=extractor.js.map