gduter.utils 源代码

import base64
import random
import re
import json
from typing import Optional
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

from .exception import *


[文档] def random_string(length: int) -> str: """生成指定长度的随机字符串。 该字符串由大小写字母和数字组成,适用于生成加密相关的随机值。 Args: length (int): 要生成的随机字符串的长度。 Returns: str: 生成的随机字符串。 """ charset = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678" return "".join(random.choices(charset, k=length))
[文档] def encrypt_password(password: str, salt: bytes) -> str: """使用 AES-CBC 模式加密密码。 该方法使用 AES(高级加密标准)算法的 CBC(密码块链接)模式对密码进行加密。 加密过程中会生成一个随机前缀和一个随机初始化向量(IV), 并使用 PKCS7 填充确保明文长度符合 AES 的块大小要求。 Args: password (str): 要加密的密码字符串。 salt (bytes): 用于加密的 16 字节盐值。 Returns: str: Base64 编码后的加密字符串。 """ # 生成 64 字节的随机前缀 random_prefix = random_string(64) # 将随机前缀和密码连接 plaintext = random_prefix.encode() + password.encode("utf-8") # 生成 16 字节的随机 IV iv = random_string(AES.block_size).encode() # 创建 AES cipher 对象,使用 CBC 模式 cipher = AES.new(key=salt, mode=AES.MODE_CBC, iv=iv) # 使用 PKCS7 填充明文 padded_plaintext = pad(plaintext, AES.block_size) # 加密 ciphertext = cipher.encrypt(padded_plaintext) # 进行 Base64 编码 return base64.b64encode(ciphertext).decode("utf-8")
[文档] def get_salt_and_execution_from_html(html: str) -> tuple[Optional[str], Optional[str]]: """从 HTML 内容中提取 salt 和 execution 的值。 该方法使用正则表达式在给定的 HTML 字符串中查找 `pwdEncryptSalt` 和 `execution` 的值。 Args: html (str): 包含 salt 和 execution 值的 HTML 字符串。 Returns: tuple[Optional[str], Optional[str]]: 一个元组,包含提取出的 salt 和 execution 值。 如果未找到,则对应的值为 None。 Raises: HTMLExtractionError: 当未能成功提取到 salt 或 execution 中的任何一个时抛出。 """ salt_match = re.search(r'id="pwdEncryptSalt" value="([^"]*)"', html) execution_match = re.search(r'name="execution" value="([^"]*)"', html) salt = salt_match.group(1) if salt_match else None execution = execution_match.group(1) if execution_match else None if salt is None or execution is None: raise HTMLExtractionError("未能从 HTML 中提取到 salt 或 execution。") return salt.strip() if salt else None, execution
[文档] def process_student_courses_from_data(data: str) -> list[dict]: """从包含学生课程信息的html内容中提取并处理课程数据。 该函数接收一个表示学生课程信息的html内容,并将其转换为包含更易于使用的键的字典列表。 Args: data (str): 包含学生课程信息的网页信息。 Returns: list[dict]: 处理后的课程信息字典列表。 """ match = re.search(r"var kbxx = (\[.*?\]);", data, re.S) if match: course_string_data = match.group(1) else: return [] original_courses = json.loads(course_string_data) courses = [ { "course_name": course["kcmc"], # 课程名称 "course_code": course["kcbh"], # 课程代码 "class_name": sorted(course["jxbmc"].split(",")), # 班级名称(上课班级) "class_times": sorted(list(map(int, course["jcdm2"].split(",")))), # 上课节次 "teaching_weeks": sorted(list(map(int, course["zcs"].split(",")))), # 上课周 "weekday": course["xq"], # 星期几上课 "location": course["jxcdmcs"], # 上课地点 "teacher_name": course["teaxms"], # 老师名称 } for course in original_courses ] return courses
if __name__ == "__main__": pass