|
const fs = require('fs'); |
|
const path = require('path'); |
|
const csv = require('csv-parser'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
async function extractCookiesFromCsv(csvFilePath) { |
|
return new Promise((resolve, reject) => { |
|
try { |
|
|
|
if (!fs.existsSync(csvFilePath)) { |
|
console.error(`CSV文件不存在: ${csvFilePath}`); |
|
return resolve([]); |
|
} |
|
|
|
|
|
const fileContent = fs.readFileSync(csvFilePath, 'utf8'); |
|
console.log(`文件内容前200个字符: ${fileContent.substring(0, 200)}`); |
|
|
|
|
|
if (!fileContent || fileContent.trim() === '') { |
|
console.error('CSV文件为空'); |
|
return resolve([]); |
|
} |
|
|
|
|
|
const cookies = []; |
|
|
|
|
|
const jwtRegex = /ey[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g; |
|
const jwtMatches = fileContent.match(jwtRegex); |
|
|
|
if (jwtMatches && jwtMatches.length > 0) { |
|
console.log(`直接从文件内容中提取到 ${jwtMatches.length} 个JWT token格式的Cookie`); |
|
jwtMatches.forEach(match => { |
|
if (!cookies.includes(match)) { |
|
cookies.push(match); |
|
} |
|
}); |
|
} |
|
|
|
|
|
const hasTokenKeyword = fileContent.includes('token'); |
|
const hasUserPrefix = fileContent.includes('user_'); |
|
console.log(`文件包含"token"关键字: ${hasTokenKeyword}`); |
|
console.log(`文件包含"user_"前缀: ${hasUserPrefix}`); |
|
|
|
|
|
if (hasUserPrefix) { |
|
const oldFormatCookies = extractCookiesFromText(fileContent); |
|
if (oldFormatCookies.length > 0) { |
|
console.log(`从文件内容中提取到 ${oldFormatCookies.length} 个旧格式Cookie`); |
|
oldFormatCookies.forEach(cookie => { |
|
if (!cookies.includes(cookie)) { |
|
cookies.push(cookie); |
|
} |
|
}); |
|
} |
|
} |
|
|
|
|
|
if (cookies.length > 0) { |
|
console.log(`总共提取到 ${cookies.length} 个Cookie`); |
|
return resolve(validateCookies(cookies)); |
|
} |
|
|
|
|
|
const possibleTokenFields = ['token', 'cookie', 'value', 'Token', 'Cookie', 'Value', 'jwt', 'JWT']; |
|
|
|
fs.createReadStream(csvFilePath) |
|
.pipe(csv()) |
|
.on('data', (row) => { |
|
|
|
for (const field of possibleTokenFields) { |
|
if (row[field]) { |
|
|
|
if (row[field].startsWith('ey') && row[field].includes('.')) { |
|
if (!cookies.includes(row[field])) { |
|
cookies.push(row[field]); |
|
} |
|
break; |
|
} |
|
|
|
else if (row[field].includes('user_')) { |
|
if (!cookies.includes(row[field])) { |
|
cookies.push(row[field]); |
|
} |
|
break; |
|
} |
|
} |
|
} |
|
|
|
|
|
if (cookies.length === 0) { |
|
for (const field in row) { |
|
if (row[field] && typeof row[field] === 'string') { |
|
|
|
if (row[field].startsWith('ey') && row[field].includes('.')) { |
|
if (!cookies.includes(row[field])) { |
|
cookies.push(row[field]); |
|
} |
|
break; |
|
} |
|
|
|
else if (row[field].includes('user_')) { |
|
if (!cookies.includes(row[field])) { |
|
cookies.push(row[field]); |
|
} |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
}) |
|
.on('end', () => { |
|
console.log(`从CSV解析中提取到 ${cookies.length} 个Cookie`); |
|
|
|
|
|
if (cookies.length === 0) { |
|
console.log('尝试按行读取文件...'); |
|
const lines = fileContent.split('\n'); |
|
for (const line of lines) { |
|
|
|
if (line.includes('ey')) { |
|
const jwtMatches = line.match(jwtRegex); |
|
if (jwtMatches) { |
|
jwtMatches.forEach(match => { |
|
if (!cookies.includes(match)) { |
|
cookies.push(match); |
|
} |
|
}); |
|
} |
|
} |
|
|
|
|
|
if (line.includes('user_')) { |
|
const extractedCookies = extractCookiesFromText(line); |
|
extractedCookies.forEach(cookie => { |
|
if (!cookies.includes(cookie)) { |
|
cookies.push(cookie); |
|
} |
|
}); |
|
} |
|
} |
|
console.log(`按行读取后提取到 ${cookies.length} 个Cookie`); |
|
} |
|
|
|
|
|
const validatedCookies = validateCookies(cookies); |
|
|
|
resolve(validatedCookies); |
|
}) |
|
.on('error', (error) => { |
|
console.error('解析CSV文件时出错:', error); |
|
|
|
|
|
if (cookies.length > 0) { |
|
console.log(`解析出错但已提取到 ${cookies.length} 个Cookie,进行验证后返回`); |
|
resolve(validateCookies(cookies)); |
|
} else { |
|
|
|
console.log('尝试其他方法提取Cookie...'); |
|
|
|
|
|
const jwtMatches = fileContent.match(jwtRegex); |
|
if (jwtMatches) { |
|
jwtMatches.forEach(match => { |
|
if (!cookies.includes(match)) { |
|
cookies.push(match); |
|
} |
|
}); |
|
} |
|
|
|
|
|
const oldFormatCookies = extractCookiesFromText(fileContent); |
|
oldFormatCookies.forEach(cookie => { |
|
if (!cookies.includes(cookie)) { |
|
cookies.push(cookie); |
|
} |
|
}); |
|
|
|
console.log(`通过其他方法提取到 ${cookies.length} 个Cookie`); |
|
resolve(validateCookies(cookies)); |
|
} |
|
}); |
|
} catch (error) { |
|
console.error('提取Cookie时出错:', error); |
|
reject(error); |
|
} |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function extractCookiesFromText(text) { |
|
const cookies = []; |
|
|
|
|
|
const oldFormatRegex = /user_[a-zA-Z0-9%]+%3A%3A[a-zA-Z0-9%\.\_\-]+/g; |
|
const oldFormatMatches = text.match(oldFormatRegex); |
|
|
|
if (oldFormatMatches) { |
|
oldFormatMatches.forEach(match => { |
|
if (!cookies.includes(match)) { |
|
cookies.push(match); |
|
} |
|
}); |
|
} |
|
|
|
|
|
const jwtRegex = /ey[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g; |
|
const jwtMatches = text.match(jwtRegex); |
|
|
|
if (jwtMatches) { |
|
jwtMatches.forEach(match => { |
|
if (!cookies.includes(match)) { |
|
cookies.push(match); |
|
} |
|
}); |
|
} |
|
|
|
return cookies; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function validateCookies(cookies) { |
|
return cookies.filter(cookie => { |
|
|
|
if (cookie.startsWith('ey') && cookie.includes('.')) { |
|
const parts = cookie.split('.'); |
|
|
|
if (parts.length === 3) { |
|
return true; |
|
} else { |
|
console.warn(`检测到不完整的JWT(新格式): ${cookie}`); |
|
return false; |
|
} |
|
} |
|
|
|
else if (cookie.includes('%3A%3A')) { |
|
const parts = cookie.split('%3A%3A'); |
|
if (parts.length === 2) { |
|
const jwt = parts[1]; |
|
|
|
if (jwt.includes('.') && jwt.split('.').length === 3) { |
|
return true; |
|
} else { |
|
console.warn(`检测到不完整的JWT(旧格式): ${cookie}`); |
|
return false; |
|
} |
|
} |
|
} |
|
return true; |
|
}); |
|
} |
|
|
|
module.exports = { |
|
extractCookiesFromCsv |
|
}; |