aa48145557
体检修复:启动日志不再打印 AUTH_TOKEN、密钥可清空、推送失败不占整段冷却、目录名与文案统一成 plugins/。
53 lines
1.7 KiB
Python
53 lines
1.7 KiB
Python
"""登录链路:base64 账号密码、图形验证码识别、ITLMS 换票。"""
|
||
import base64
|
||
import re
|
||
import time
|
||
|
||
from . import http
|
||
|
||
_OCR = None
|
||
|
||
|
||
def b64(text):
|
||
return base64.b64encode(str(text).encode("utf-8")).decode()
|
||
|
||
|
||
def ocr():
|
||
"""4 位图形验证码:ddddocr 离线识别。"""
|
||
global _OCR
|
||
if _OCR is None:
|
||
try:
|
||
import ddddocr
|
||
except Exception as e:
|
||
raise RuntimeError("登录要过图形验证码,需要先装 ddddocr(pip install ddddocr):%s" % e)
|
||
_OCR = ddddocr.DdddOcr(show_ad=False)
|
||
return _OCR
|
||
|
||
|
||
def captcha(s):
|
||
raw = s.get(http.G + "/login/readCaptcha.action?d=%.6f" % time.time(), timeout=30).text
|
||
return base64.b64decode(raw.strip().strip('"').split(",", 1)[-1])
|
||
|
||
|
||
def login_error(s):
|
||
html = s.get(http.G + "/login.jsp", timeout=30).text
|
||
m = re.search(r'id="errorText"[^>]*>([^<]*)<', html)
|
||
return (m.group(1).strip() if m else "")
|
||
|
||
|
||
def sso(s):
|
||
"""jsglpt 会话换 ITLMS 票,票按 `ITLMS-xxx||ticketId` 两段交给 jsxx。
|
||
|
||
交接入口来自 jsglpt 首页那个隐藏表单:
|
||
`GET https://jsxx.gds.edu.cn/nts/loginToStoreByAccount?ticket=&ticketId=`
|
||
"""
|
||
r = s.post(http.G + "/teacher/ssoItlmsGxkTicket.action?verificaCode=true&page=", timeout=30)
|
||
ticket = (r.text or "").strip()
|
||
if not ticket.startswith("ITLMS-") or "||" not in ticket:
|
||
raise http.expired("取 ITLMS 票失败:%s" % (ticket[:80] or "空响应"))
|
||
t, tid = ticket.split("||", 1)
|
||
q = s.get(http.X + "/nts/loginToStoreByAccount", params={"ticket": t, "ticketId": tid}, timeout=30)
|
||
if "logout" not in q.text and "我的课程" not in q.text:
|
||
raise http.expired("带票进学习平台失败,票可能已失效")
|
||
return s
|