const puppeteer = require('puppeteer'); const getCaptcha = require('../Captcha/tesseract'); const axios = require('axios'); class icCookie { constructor() { console.log('启动浏览器服务') this.browser = 0 } async getLoginUrl() { return new Promise(async (resolve, reject) => { const url1 = 'https://ic.ctbu.edu.cn/ic-web/auth/address?finalAddress=https:%2F%2Fic.ctbu.edu.cn&errPageUrl=https:%2F%2Fic.ctbu.edu.cn%2F%23%2Ferror&manager=false&consoleType=16'; try { const res1 = await axios.get(url1, { maxRedirects: 5, // 增加最大重定向次数 validateStatus: function (status) { return (status >= 200 && status < 300) || status === 302; // 接受 302 重定向 } }); let redirectUrl = res1.data.data || res1.headers.location; if (!redirectUrl) { reject('无法获取登录 URL'); return; } resolve(redirectUrl); } catch (error) { if (error.response) { const redirectUrl = error.response.headers.location; if (redirectUrl) { resolve(redirectUrl); } else { reject(error); } } else { reject(error); } } }); } async refresh(page) { page.evaluate(async () => { // window.location.reload(); await refreshCode(); }); } async getAuthcode(page) { return new Promise(async (resolve, reject) => { try { let base64Image = ''; const url = await this.getLoginUrl(); page.goto(url); page.on('response', async (response) => { if (response.url().includes('kaptcha?time=')) { const buffer = await response.buffer(); base64Image = buffer.toString('base64'); const authcodeResult = await getCaptcha(base64Image); if (!authcodeResult.success) { return await this.refresh(page); } const authcode = authcodeResult.msg; resolve(authcode); } }); // 超时处理 setTimeout(async () => { if (base64Image === '') { await this.refresh(page); } }, 5000); } catch (error) { console.log(error.stack) reject(error); } }); } async tryLogin(page, username, password, authcode) { return new Promise(async (resolve, reject) => { try { await page.waitForSelector('#username'); await page.waitForSelector('#authcode'); await page.waitForSelector('#password'); await page.waitForSelector('#fm1'); await page.evaluate(async (username, password, authcode) => { document.querySelector("#username").value = username; document.querySelector("#authcode").value = authcode; function checkForm() { var key = new RSAUtils.getKeyPair(public_exponent, "", Modulus); var reversedPwd = password.split("").reverse().join(""); var encrypedPwd = RSAUtils.encryptedString(key, reversedPwd); document.querySelector("#password").value = encrypedPwd; document.querySelector("#fm1").submit(); return { public_exponent, Modulus, encrypedPwd, authcode }; } return checkForm(); }, username, password, authcode); // 响应处理 page.on('response', async (response) => { if (response.status() >= 300 && response.status() < 400) { return resolve(); } if (response.url().includes('login?v=')) { const responseText = await response.text(); if (responseText.includes('验证码输入有误') || responseText.includes('必须录入验证码')) { reject({ code: -603, msg: '验证码输入有误' }); } else if (responseText.includes('用户名或密码错误')) { reject({ code: -600, msg: '用户名或密码错误' }); } else if (responseText.includes('锁定')) { reject({ code: -601, msg: '账户被锁定' }); } else { reject({ code: -604, msg: '未知错误' }); } } }); } catch (error) { reject({ code: -602, msg: error.message }); } }); } async loading(username, password) { if (this.browser.length >= 5) { return { code: -666, msg: '并发数量达到上限,请稍后再试' }; } let browser; this.browser += 1 try { browser = await puppeteer.launch({ headless: true, timeout: 60000 }); const page = await browser.newPage(); page.setDefaultTimeout(30000); const authcode = await this.getAuthcode(page); await this.tryLogin(page, username, password, authcode); let cookie = await this.getCookie(page); cookie = cookie.split(';')[0] return { code: 0, msg: cookie }; } catch (error) { console.error('登录过程错误:', error); return { code: -600, msg: error.message }; } finally { this.browser -= 1 if (browser) { await browser.close(); } } } async getCookie (page) { return new Promise((resolve, reject) => { page.on('response', async response => { if (response.url().includes('https://ic.ctbu.edu.cn/ic-web//auth/token?uuid=')) { // 获取响应头中的 Set-Cookie const cookies = response.headers()['set-cookie']; if (cookies) { resolve(cookies); } else { reject('No cookies found in response headers'); } } }); }); }; } let IcCookie = new icCookie() module.exports = IcCookie;