Files
CursorBin/background.js
2026-01-13 11:28:37 +08:00

551 lines
18 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 虚拟身份池
* 用于生成随机持卡人姓名
*/
const FIRST_NAMES = ["John", "Michael", "David", "James", "Robert", "William", "Richard", "Joseph", "Charles", "Thomas", "Christopher", "Daniel", "Matthew", "Anthony", "Mark", "Donald", "Steven", "Paul", "Andrew", "Joshua", "Kenneth", "Kevin", "Brian", "Mary", "Patricia", "Jennifer", "Linda", "Barbara", "Elizabeth", "Susan", "Jessica", "Sarah", "Karen", "Nancy", "Lisa", "Betty", "Margaret", "Sandra"];
const LAST_NAMES = ["Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis", "Rodriguez", "Martinez", "Hernandez", "Lopez", "Gonzalez", "Wilson", "Anderson", "Thomas", "Taylor", "Moore", "Jackson", "Martin", "Lee", "Thompson", "White", "Harris", "Sanchez", "Clark", "Ramirez", "Lewis", "Robinson", "Walker", "Young"];
/**
* 默认地址配置
*/
const DEFAULT_ADDRESSES = [{
name: "John Smith",
firstName: "John",
lastName: "Smith",
address1: "69 Adams Street",
address2: "",
city: "Brooklyn",
state: "New York",
stateCode: "NY",
postal: "11201",
countryText: "United States",
countryValue: "US"
}, {
name: "Michael Johnson",
firstName: "Michael",
lastName: "Johnson",
address1: "3511 Carlisle Avenue",
address2: "",
city: "Covington",
state: "Kentucky",
stateCode: "KY",
postal: "41015",
countryText: "United States",
countryValue: "US"
}];
// ==========================================
// 算法工具函数 (Luhn Algorithm)
// ==========================================
function randomChoice(array) {
return array[Math.floor(Math.random() * array.length)];
}
/**
* 根据卡号前缀识别卡组织类型
*/
function getCardType(cardNumber) {
const patterns = {
Visa: /^4/,
Mastercard: /^5[1-5]/,
"American Express": /^3[47]/,
Discover: /^6(?:011|5)/,
JCB: /^35/,
"Diners Club": /^3(?:0[0-5]|[68])/,
Maestro: /^(?:5[0678]\d\d|6304|6390|67\d\d)/,
UnionPay: /^62/
};
for (const [type, regex] of Object.entries(patterns)) {
if (regex.test(cardNumber)) {
return type;
}
}
return "Unknown";
}
/**
* 计算 Luhn 校验位 (模10算法)
* 用于确保生成的卡号在数学上是有效的
*/
function calculateLuhnCheckDigit(digits) {
let sum = 0;
let shouldDouble = true;
for (let i = digits.length - 1; i >= 0; i--) {
let digit = parseInt(digits[i]);
if (shouldDouble) {
digit *= 2;
if (digit > 9) {
digit -= 9;
}
}
sum += digit;
shouldDouble = !shouldDouble;
}
return (10 - sum % 10) % 10;
}
/**
* 验证卡号是否符合 Luhn 算法
*/
function validateLuhn(number) {
const digits = number.replace(/\D/g, "");
let sum = 0;
let shouldDouble = false;
for (let i = digits.length - 1; i >= 0; i--) {
let digit = parseInt(digits[i]);
if (shouldDouble) {
digit *= 2;
if (digit > 9) {
digit -= 9;
}
}
sum += digit;
shouldDouble = !shouldDouble;
}
return sum % 10 === 0;
}
/**
* 生成符合校验规则的卡号
* @param {string} binPattern - BIN 格式 (如 "552461xxxxxxxxxx")
*/
function generateValidCardNumber(binPattern) {
let rawNumber = "";
// 1. 填充随机数
for (let i = 0; i < binPattern.length - 1; i++) {
if (binPattern[i] === "x" || binPattern[i] === "X") {
rawNumber += Math.floor(Math.random() * 10);
} else {
rawNumber += binPattern[i];
}
}
// 2. 计算最后一位校验码
const checkDigit = calculateLuhnCheckDigit(rawNumber);
rawNumber += checkDigit;
return rawNumber;
}
function generateExpiryDate() {
const now = new Date();
const currentYear = now.getFullYear();
const currentMonth = now.getMonth() + 1;
// 随机生成 1 到 60 个月后的日期
const randomMonths = Math.floor(Math.random() * 60) + 1;
let targetMonth = currentMonth + randomMonths;
let targetYear = currentYear;
while (targetMonth > 12) {
targetMonth -= 12;
targetYear += 1;
}
return {
month: targetMonth.toString().padStart(2, "0"),
year: targetYear.toString()
};
}
function generateCVV(length = 3) {
let cvv = "";
for (let i = 0; i < length; i++) {
cvv += Math.floor(Math.random() * 10);
}
return cvv;
}
// ==========================================
// 核心生成逻辑
// ==========================================
/**
* 本地生成模式:使用内置算法生成卡号
*/
function generateCardsLocally(bin, amount = 10) {
const cards = [];
const uniqueSet = new Set();
console.log(`🎲 Generating ${amount} valid cards from BIN: ${bin}`);
let attempts = 0;
const maxAttempts = amount * 10;
while (cards.length < amount && attempts < maxAttempts) {
attempts++;
const number = generateValidCardNumber(bin);
if (uniqueSet.has(number)) continue;
if (!validateLuhn(number)) {
console.warn("⚠️ Generated invalid card (should not happen):", number);
continue;
}
uniqueSet.add(number);
const expiry = generateExpiryDate();
const cvv = generateCVV(3);
const type = getCardType(number);
cards.push({
serial_number: cards.length + 1,
card_number: number,
expiry_month: expiry.month,
expiry_year: expiry.year,
cvv: cvv,
card_type: type,
full_format: `${number}|${expiry.month}|${expiry.year}|${cvv}`,
luhn_valid: true
});
}
console.log(`[cardbingenerator] Successfully generated ${cards.length} valid cards`);
// 最后的完整性检查
const invalid = cards.filter(c => !validateLuhn(c.card_number));
if (invalid.length > 0) {
console.error(`❌ Found ${invalid.length} invalid cards!`);
} else {
console.log("[cardbingenerator] All cards passed Luhn validation");
}
// 统计卡种分布
const stats = {};
cards.forEach(c => {
stats[c.card_type] = (stats[c.card_type] || 0) + 1;
});
console.log("📊 Card types:", stats);
return cards;
}
/**
* 简单生成模式:仅生成随机数,不进行 Luhn 校验 (用于某些不需要校验的测试场景)
*/
function generateCardsSimple(bin, amount = 10) {
const cards = [];
const uniqueSet = new Set();
console.log(`🎲 Generating ${amount} cards (no validation) from BIN: ${bin}`);
for (let i = 0; i < amount; i++) {
let number = "";
for (let j = 0; j < bin.length; j++) {
if (bin[j] === "x" || bin[j] === "X") {
number += Math.floor(Math.random() * 10);
} else {
number += bin[j];
}
}
if (uniqueSet.has(number)) {
i--;
continue;
}
uniqueSet.add(number);
const expiry = generateExpiryDate();
const cvv = generateCVV(3);
const type = getCardType(number);
cards.push({
serial_number: i + 1,
card_number: number,
expiry_month: expiry.month,
expiry_year: expiry.year,
cvv: cvv,
card_type: type,
full_format: `${number}|${expiry.month}|${expiry.year}|${cvv}`,
luhn_valid: false
});
}
console.log(`[cardbingenerator] Generated ${cards.length} cards (simple mode)`);
return cards;
}
// ==========================================
// 远程生成逻辑 (AKR-Gen)
// ==========================================
/**
* 远程生成模式:操控第三方网站 (akr-gen.bigfk.com) 生成卡号
* 当本地算法不满足需求时使用
*/
async function generateCardsFromAKR(bin, onComplete) {
let tab = null;
try {
console.log("[cardbingenerator] Opening AKR-gen tab...");
// 创建一个不激活的标签页(后台静默打开)
tab = await chrome.tabs.create({
url: "https://akr-gen.bigfk.com/",
active: false
});
console.log("[cardbingenerator] Waiting for page load...");
await new Promise(resolve => setTimeout(resolve, 4000));
console.log("[cardbingenerator] Filling BIN and generating cards...");
// 注入脚本自动填入BIN并点击生成
const fillResult = await chrome.scripting.executeScript({
target: { tabId: tab.id },
func: remotePage_fillAndClick,
args: [bin]
});
console.log("Fill result:", fillResult[0]?.result);
console.log("⏳ Waiting a moment before checking results...");
await new Promise(resolve => setTimeout(resolve, 2000));
console.log("📥 Getting generated cards (will wait up to 10 seconds)...");
// 注入脚本:抓取结果
const scrapeResult = await chrome.scripting.executeScript({
target: { tabId: tab.id },
func: remotePage_scrapeResults
});
console.log("[cardbingenerator] Closing AKR-gen tab...");
await chrome.tabs.remove(tab.id);
tab = null;
if (scrapeResult && scrapeResult[0] && scrapeResult[0].result) {
const parsedCards = parseScrapedCards(scrapeResult[0].result);
console.log(`[cardbingenerator] Generated ${parsedCards.length} cards`);
if (parsedCards.length > 0) {
const randomAddr = await getRandomAddress();
// 存入 storage 供 Content Script 使用
chrome.storage.local.set({
generatedCards: parsedCards,
randomData: randomAddr
});
onComplete({ success: true, cards: parsedCards });
} else {
console.error("❌ No cards generated from AKR");
onComplete({ success: false, error: "No cards generated from AKR-gen" });
}
} else {
console.error("❌ Failed to retrieve cards from result");
onComplete({ success: false, error: "Failed to retrieve cards from page" });
}
} catch (err) {
console.error("❌ Error in generateCardsFromAKR:", err);
if (tab) {
try { await chrome.tabs.remove(tab.id); } catch (e) {}
}
onComplete({ success: false, error: err.message });
}
}
// -- 以下函数会被注入到目标页面执行,不能使用外部变量 --
function remotePage_fillAndClick(bin) {
return new Promise(resolve => {
function waitForElement(selector, retries = 10, delay = 300) {
return new Promise(res => {
let count = 0;
const check = () => {
const el = document.querySelector(selector) || document.getElementById(selector.replace("#", ""));
if (el) {
res(el);
} else if (count < retries) {
count++;
setTimeout(check, delay);
} else {
res(null);
}
};
check();
});
}
waitForElement("bin").then(input => {
if (input) {
console.log("[cardbingenerator] Found BIN input, filling with:", bin);
input.value = bin;
input.dispatchEvent(new Event("input", { bubbles: true }));
input.dispatchEvent(new Event("change", { bubbles: true }));
setTimeout(() => {
waitForElement("button[type=\"submit\"]").then(btn => {
if (btn) {
console.log("[cardbingenerator] Found generate button, clicking...");
btn.click();
resolve(true);
} else {
console.error("❌ Generate button not found");
resolve(false);
}
});
}, 500);
} else {
console.error("❌ BIN input not found");
resolve(false);
}
});
});
}
function remotePage_scrapeResults() {
return new Promise(resolve => {
function waitLoop(retries = 20, delay = 500) {
let count = 0;
const check = () => {
const resultArea = document.getElementById("result");
if (resultArea && resultArea.value.trim()) {
console.log("[cardbingenerator] Found generated cards:", resultArea.value.split("\n").length, "lines");
resolve(resultArea.value);
} else if (count < retries) {
count++;
console.log(`[cardbingenerator] Waiting for cards... attempt ${count}/${retries}`);
setTimeout(check, delay);
} else {
console.error("❌ Timeout waiting for cards");
resolve("");
}
};
check();
}
waitLoop();
});
}
// ----------------------------------------------------
function parseScrapedCards(text) {
if (!text) return [];
const lines = text.trim().split("\n");
const cards = [];
lines.forEach((line, index) => {
if (line.trim()) {
const parts = line.trim().split("|");
if (parts.length === 4) {
cards.push({
serial_number: index + 1,
card_number: parts[0],
expiry_month: parts[1],
expiry_year: parts[2],
cvv: parts[3],
full_format: line.trim()
});
}
}
});
return cards;
}
/**
* 辅助:获取随机地址
*/
async function getRandomAddress() {
return new Promise(resolve => {
chrome.storage.local.get(["customAddresses"], data => {
const custom = data.customAddresses || [];
const pool = [...custom, ...DEFAULT_ADDRESSES];
if (pool.length === 0) {
resolve(DEFAULT_ADDRESSES[0]);
} else {
const selected = randomChoice(pool);
resolve(selected);
}
});
});
}
// ==========================================
// 数据清理逻辑 (Browsing Data API)
// ==========================================
async function clearStripeBrowsingData(sendResponse) {
try {
const domains = ["stripe.com", "checkout.stripe.com", "js.stripe.com", "hooks.stripe.com"];
// 1. 深度清理 Cookies (针对特定域)
for (const domain of domains) {
const cookies = await chrome.cookies.getAll({ domain: domain });
for (const cookie of cookies) {
await chrome.cookies.remove({
url: "https://" + cookie.domain + cookie.path,
name: cookie.name
});
}
}
// 2. 清理浏览器缓存和存储 (针对特定 Origin)
await chrome.browsingData.remove({
origins: domains.map(d => "https://" + d)
}, {
cache: true,
cookies: true,
localStorage: true,
indexedDB: true,
serviceWorkers: true,
cacheStorage: true
});
console.log("[cardbingenerator] Deep clear completed for Stripe domains");
if (sendResponse) sendResponse({ success: true });
} catch (err) {
console.error("Error in deep clear:", err);
if (sendResponse) sendResponse({ success: false, error: err.message });
}
}
// ==========================================
// 消息监听与路由
// ==========================================
// 安装时初始化默认 BIN
chrome.runtime.onInstalled.addListener(() => {
chrome.storage.local.get(["currentBin", "binHistory"], data => {
if (!data.currentBin) {
chrome.storage.local.set({
currentBin: "552461xxxxxxxxxx",
binHistory: ["552461xxxxxxxxxx"]
});
}
});
});
// 主消息处理器
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "generateCards") {
// 路由到生成逻辑
generateCardsHandler(request.bin, request.useValidation, sendResponse);
return true; // 保持消息通道打开以进行异步响应
}
if (request.action === "clearBrowsingData") {
// 路由到清理逻辑
clearStripeBrowsingData(sendResponse);
return true;
}
});
async function generateCardsHandler(bin, useValidation = true, sendResponse) {
try {
console.log(`[cardbingenerator] Starting card generation... (Luhn: ${useValidation ? "ON" : "OFF"})`);
// 根据配置决定是验证 Luhn 还是简单生成
const cards = useValidation ?
generateCardsLocally(bin, 10) :
generateCardsSimple(bin, 10);
if (cards.length > 0) {
const address = await getRandomAddress();
// 将结果存入 storage这样 Content Script (第一部分代码) 就能读到了
chrome.storage.local.set({
generatedCards: cards,
randomData: address
});
console.log(`[cardbingenerator] Generated and saved ${cards.length} cards`);
sendResponse({ success: true, cards: cards });
} else {
console.error("❌ No cards generated");
sendResponse({ success: false, error: "Failed to generate cards" });
}
} catch (err) {
console.error("❌ Error in generateCardsHandler:", err);
sendResponse({ success: false, error: err.message });
}
}