webvpnCookie.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /**
  2. * WebVPN 会话 Cookie:调用 ic-ctbu-backend-py /webvpnlogin,并可 Redis 缓存。
  3. */
  4. const axios = require('axios')
  5. const config = require('../../config.json')
  6. const db = require('../../plugin/DataBase/db')
  7. const Redis = require('../../plugin/DataBase/Redis')
  8. const CACHE_PREFIX = 'webvpn_cookie:'
  9. const CACHE_TTL_SEC = 25 * 60
  10. function webvpnLoginBaseUrl() {
  11. const u = config.webvpnLoginBaseUrl || config.url3
  12. return (u && String(u).replace(/\/$/, '')) || ''
  13. }
  14. function isProbablyVpnLoginHtml(body) {
  15. if (typeof body !== 'string') return false
  16. return (
  17. body.includes('lyuapServer') ||
  18. body.includes('ivpn') ||
  19. body.includes('统一认证') ||
  20. body.includes('rump_frontend/login')
  21. )
  22. }
  23. async function fetchWebVpnCookieFromPy(username, password) {
  24. const base = webvpnLoginBaseUrl()
  25. if (!base) {
  26. throw new Error('未配置 webvpnLoginBaseUrl')
  27. }
  28. const url = `${base}/webvpnlogin`
  29. const res = await axios.post(
  30. url,
  31. { username, password },
  32. { timeout: 120000, proxy: false, validateStatus: () => true }
  33. )
  34. const data = res.data
  35. if (!data || data.code !== 0 || !data.webvpn_cookie) {
  36. throw new Error(data?.msg || 'WebVPN 登录失败')
  37. }
  38. return String(data.webvpn_cookie)
  39. }
  40. async function getJwPasswordForUser(uuid, jwUsername) {
  41. const rows = await db.query(
  42. 'SELECT password FROM jw_account WHERE create_user = ? AND username = ? AND state IN (0, 1)',
  43. [uuid, jwUsername]
  44. )
  45. if (!rows || rows.length !== 1 || !rows[0].password) {
  46. throw new Error('未绑定教务账号或账号不可用,请先绑定教务账号')
  47. }
  48. return rows[0].password
  49. }
  50. /**
  51. * @param {string} createUserUuid
  52. * @param {string} jwUsername 教务登录名
  53. * @param {{ skipCache?: boolean }} [opts]
  54. */
  55. async function getWebVpnCookieHeader(createUserUuid, jwUsername, opts = {}) {
  56. const skipCache = opts.skipCache === true
  57. const key = `${CACHE_PREFIX}${createUserUuid}:${jwUsername}`
  58. if (!skipCache) {
  59. const cached = await Redis.get(key)
  60. if (cached) return cached
  61. }
  62. const pwd = await getJwPasswordForUser(createUserUuid, jwUsername)
  63. const cookie = await fetchWebVpnCookieFromPy(jwUsername, pwd)
  64. await Redis.set(key, cookie, { EX: CACHE_TTL_SEC })
  65. return cookie
  66. }
  67. async function invalidateWebVpnCookie(createUserUuid, jwUsername) {
  68. const key = `${CACHE_PREFIX}${createUserUuid}:${jwUsername}`
  69. await Redis.del(key)
  70. }
  71. module.exports = {
  72. webvpnLoginBaseUrl,
  73. isProbablyVpnLoginHtml,
  74. fetchWebVpnCookieFromPy,
  75. getWebVpnCookieHeader,
  76. invalidateWebVpnCookie,
  77. CACHE_TTL_SEC
  78. }