|
#!/Users/bytedance/.bun/bin/bun |
|
import { $ } from 'bun'; |
|
import crypto from "crypto"; |
|
import { Database } from "bun:sqlite"; |
|
|
|
const salt = "saltysalt"; // 盐 |
|
const iv = "".padStart(16, " "); // 16-byte empty string (spaces) |
|
const keyLengthBits = 128; // 长度 (bits) |
|
const iterations = 1003; // 迭代次数 |
|
const password = await getChromeSecurityKey(); |
|
|
|
async function getCookieFiles() { |
|
const chromeDir = `${Bun.env.HOME}/Library/Application Support/Google/Chrome`; |
|
const entries = await $`ls ${chromeDir}`.text(); |
|
const cookieFiles = []; |
|
for (const entry of entries.split('\n')) { |
|
const dbPath = `${chromeDir}/${entry}/Cookies`; |
|
if (await Bun.file(dbPath).exists()) { |
|
cookieFiles.push(dbPath); |
|
} |
|
} |
|
return cookieFiles; |
|
} |
|
|
|
async function getCookie(cookieName: string, file: string) { |
|
const db = new Database(file, { readonly: true }); |
|
const cookies = db.query(`SELECT host_key, name, value, encrypted_value FROM cookies WHERE name = '${cookieName}'`).all(); |
|
if (cookies.length > 0) { |
|
return cookies[0]; |
|
} |
|
} |
|
|
|
async function getChromeSecurityKey() { |
|
const key = await $`security find-generic-password -a "Chrome" -w`.text(); |
|
return key.trim(); |
|
} |
|
|
|
async function decryptCookie(encryptedCookie: Uint8Array) { |
|
const key = crypto.pbkdf2Sync( |
|
password, |
|
Buffer.from(salt, "utf8"), |
|
iterations, |
|
keyLengthBits / 8, // convert bits → bytes |
|
"sha1" |
|
); |
|
|
|
// ---- AES-128-CBC Decrypt ---- |
|
const decipher = crypto.createDecipheriv( |
|
"aes-128-cbc", |
|
key, |
|
Buffer.from(iv, "utf8") |
|
); |
|
|
|
// Equivalent to Arrays.copyOfRange(encryptedCookie, 3, encryptedCookie.length) |
|
const encryptedPayload = encryptedCookie.subarray(3); |
|
|
|
const decrypted = |
|
Buffer.concat([ |
|
decipher.update(encryptedPayload), |
|
decipher.final() |
|
]); |
|
|
|
// ---- Result ---- |
|
const textDecoder = new TextDecoder('utf-8'); |
|
console.log(textDecoder.decode(decrypted.slice(32))); |
|
} |
|
|
|
if (Bun.argv.length !== 3) { |
|
console.log(`This script find cookie by name in Chrome cookies database. |
|
It will try to find all cookie files in any Chrome profile directory and return the first one found. |
|
$ Usage: get-cookie <cookie-name>`); |
|
process.exit(0); |
|
} |
|
|
|
const cookieFiles = await getCookieFiles(); |
|
for (const file of cookieFiles) { |
|
const cookie = await getCookie(Bun.argv[2], file); |
|
if (cookie) { |
|
if (cookie.value) console.log(cookie.value); |
|
else { |
|
await decryptCookie(cookie.encrypted_value); |
|
process.exit(0); |
|
} |
|
} |
|
} |
|
|
|
console.log('Not found'); |
|
process.exit(1); |