IcCookie.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. const puppeteer = require('puppeteer');
  2. const getCaptcha = require('../Captcha/tesseract');
  3. const axios = require('axios');
  4. class icCookie {
  5. constructor() {
  6. console.log('启动浏览器服务')
  7. this.browser = 0
  8. }
  9. async getLoginUrl() {
  10. return new Promise(async (resolve, reject) => {
  11. 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';
  12. try {
  13. const res1 = await axios.get(url1, {
  14. maxRedirects: 5, // 增加最大重定向次数
  15. validateStatus: function (status) {
  16. return (status >= 200 && status < 300) || status === 302; // 接受 302 重定向
  17. }
  18. });
  19. let redirectUrl = res1.data.data || res1.headers.location;
  20. if (!redirectUrl) {
  21. reject('无法获取登录 URL');
  22. return;
  23. }
  24. resolve(redirectUrl);
  25. } catch (error) {
  26. if (error.response) {
  27. const redirectUrl = error.response.headers.location;
  28. if (redirectUrl) {
  29. resolve(redirectUrl);
  30. } else {
  31. reject(error);
  32. }
  33. } else {
  34. reject(error);
  35. }
  36. }
  37. });
  38. }
  39. async refresh(page) {
  40. page.evaluate(async () => {
  41. // window.location.reload();
  42. await refreshCode();
  43. });
  44. }
  45. async getAuthcode(page) {
  46. return new Promise(async (resolve, reject) => {
  47. try {
  48. let base64Image = '';
  49. const url = await this.getLoginUrl();
  50. page.goto(url);
  51. page.on('response', async (response) => {
  52. if (response.url().includes('kaptcha?time=')) {
  53. const buffer = await response.buffer();
  54. base64Image = buffer.toString('base64');
  55. const authcodeResult = await getCaptcha(base64Image);
  56. if (!authcodeResult.success) {
  57. return await this.refresh(page);
  58. }
  59. const authcode = authcodeResult.msg;
  60. resolve(authcode);
  61. }
  62. });
  63. // 超时处理
  64. setTimeout(async () => {
  65. if (base64Image === '') {
  66. await this.refresh(page);
  67. }
  68. }, 5000);
  69. } catch (error) {
  70. console.log(error.stack)
  71. reject(error);
  72. }
  73. });
  74. }
  75. async tryLogin(page, username, password, authcode) {
  76. return new Promise(async (resolve, reject) => {
  77. try {
  78. await page.waitForSelector('#username');
  79. await page.waitForSelector('#authcode');
  80. await page.waitForSelector('#password');
  81. await page.waitForSelector('#fm1');
  82. await page.evaluate(async (username, password, authcode) => {
  83. document.querySelector("#username").value = username;
  84. document.querySelector("#authcode").value = authcode;
  85. function checkForm() {
  86. var key = new RSAUtils.getKeyPair(public_exponent, "", Modulus);
  87. var reversedPwd = password.split("").reverse().join("");
  88. var encrypedPwd = RSAUtils.encryptedString(key, reversedPwd);
  89. document.querySelector("#password").value = encrypedPwd;
  90. document.querySelector("#fm1").submit();
  91. return { public_exponent, Modulus, encrypedPwd, authcode };
  92. }
  93. return checkForm();
  94. }, username, password, authcode);
  95. // 响应处理
  96. page.on('response', async (response) => {
  97. if (response.status() >= 300 && response.status() < 400) {
  98. return resolve();
  99. }
  100. if (response.url().includes('login?v=')) {
  101. const responseText = await response.text();
  102. if (responseText.includes('验证码输入有误') || responseText.includes('必须录入验证码')) {
  103. reject({ code: -603, msg: '验证码输入有误' });
  104. } else if (responseText.includes('用户名或密码错误')) {
  105. reject({ code: -600, msg: '用户名或密码错误' });
  106. } else if (responseText.includes('锁定')) {
  107. reject({ code: -601, msg: '账户被锁定' });
  108. } else {
  109. reject({ code: -604, msg: '未知错误' });
  110. }
  111. }
  112. });
  113. } catch (error) {
  114. reject({ code: -602, msg: error.message });
  115. }
  116. });
  117. }
  118. async loading(username, password) {
  119. if (this.browser.length >= 5) {
  120. return { code: -666, msg: '并发数量达到上限,请稍后再试' };
  121. }
  122. let browser;
  123. this.browser += 1
  124. try {
  125. browser = await puppeteer.launch({
  126. headless: true,
  127. timeout: 60000
  128. });
  129. const page = await browser.newPage();
  130. page.setDefaultTimeout(30000);
  131. const authcode = await this.getAuthcode(page);
  132. await this.tryLogin(page, username, password, authcode);
  133. let cookie = await this.getCookie(page);
  134. cookie = cookie.split(';')[0]
  135. return { code: 0, msg: cookie };
  136. } catch (error) {
  137. console.error('登录过程错误:', error);
  138. return { code: -600, msg: error.message };
  139. } finally {
  140. this.browser -= 1
  141. if (browser) {
  142. await browser.close();
  143. }
  144. }
  145. }
  146. async getCookie (page) {
  147. return new Promise((resolve, reject) => {
  148. page.on('response', async response => {
  149. if (response.url().includes('https://ic.ctbu.edu.cn/ic-web//auth/token?uuid=')) {
  150. // 获取响应头中的 Set-Cookie
  151. const cookies = response.headers()['set-cookie'];
  152. if (cookies) {
  153. resolve(cookies);
  154. } else {
  155. reject('No cookies found in response headers');
  156. }
  157. }
  158. });
  159. });
  160. };
  161. }
  162. let IcCookie = new icCookie()
  163. module.exports = IcCookie;