Warning: fopen(/www/sites/update.greasyfork.icu/index/store/temp/390226025d0a1b9c6db932963e263837.js): failed to open stream: No space left on device in /www/sites/update.greasyfork.icu/index/scriptControl.php on line 65
// ==UserScript== // @name 柠檬文采学堂线上考试工具 // @namespace http://tampermonkey.net/ // @version 2.0 // @description 柠檬文采学堂线上考试辅助工具 // @author Lizhihang // @match https://jw.wencaischool.net/ahnydx/console/ // @icon https://*/* // @grant none // @downloadURL https://update.greasyfork.icu/scripts/541692/%E6%9F%A0%E6%AA%AC%E6%96%87%E9%87%87%E5%AD%A6%E5%A0%82%E7%BA%BF%E4%B8%8A%E8%80%83%E8%AF%95%E5%B7%A5%E5%85%B7.user.js // @updateURL https://update.greasyfork.icu/scripts/541692/%E6%9F%A0%E6%AA%AC%E6%96%87%E9%87%87%E5%AD%A6%E5%A0%82%E7%BA%BF%E4%B8%8A%E8%80%83%E8%AF%95%E5%B7%A5%E5%85%B7.meta.js // ==/UserScript== (function() { 'use strict'; // 页面检测 if (!location.href.includes('/openlearning/separation/exam/index.html')) return; console.log('考试页面监听已启动'); // 创建弹窗容器 const createPopup = () => { const popup = document.createElement('div'); popup.id = 'examDataPopup'; popup.style = ` position: fixed; bottom: 0px; right: 50px; width: 500px; height: 500px; background-color: white; border: 1px solid #ccc; box-shadow: 0 0 10px rgba(0,0,0,0.2); z-index: 9999; overflow: auto; padding: 10px; `; // 弹窗标题和关闭按钮 popup.innerHTML = `

试题数据

`; document.body.appendChild(popup); // 关闭按钮事件 popup.querySelector('#closePopup').addEventListener('click', () => { popup.style.display = 'none'; }); return popup; }; // 显示弹窗 const showPopup = () => { const popup = document.getElementById('examDataPopup'); if (popup) { popup.style.display = 'block'; } }; // 在弹窗中显示数据 const displayDataInPopup = (data) => { const popupContent = document.getElementById('popupContent'); if (!popupContent) return; // 清空之前的内容 popupContent.innerHTML = ''; // 检查数据结构是否符合预期 if (!data || !data.itemInfoList) { popupContent.innerHTML = '

未获取到试题数据或数据结构不符

'; return; } // 创建表格展示数据 const table = document.createElement('table'); table.style.width = '100%'; table.style.borderCollapse = 'collapse'; table.innerHTML = ` 题号 题干 答案 `; popupContent.appendChild(table); const tbody = document.getElementById('popupTableBody'); if (!tbody) return; // 遍历试题数据 const questionData = data.itemInfoList; if (Array.isArray(questionData)) { questionData.forEach((item, index) => { const row = document.createElement('tr'); // 安全处理题干内容 const itemName = item.itemName ? item.itemName.replace(/<[^>]*>/g, '') : '无题干'; // 提取答案选项 let answers = '无答案'; if (item.itemAnswer && Array.isArray(item.itemAnswer)) { answers = item.itemAnswer.map(a => { return a.optionContent ? a.optionContent : `选项${a.optionSeq}` }).join(', '); } row.innerHTML = ` ${index + 1} ${itemName} ${answers} `; tbody.appendChild(row); }); } // 显示弹窗 showPopup(); }; // 从common.js中提取的解密函数 function decryptData(encryptedData) { if (!encryptedData) return null; try { // 检查是否是JSON格式 let responseJson = typeof encryptedData === 'string' ? JSON.parse(encryptedData) : encryptedData; // 如果存在data字段且是字符串,尝试解密 if (responseJson && typeof responseJson.data === 'string') { const decryptedStr = decrypt(responseJson.data); if (decryptedStr) { return JSON.parse(decryptedStr); } } // 如果data字段已经是对象,直接返回 if (responseJson && typeof responseJson.data === 'object') { return responseJson; } // 尝试直接解密整个响应 const decryptedStr = decrypt(encryptedData); return decryptedStr ? JSON.parse(decryptedStr) : responseJson; } catch (e) { console.error('解密过程中发生错误:', e); return null; } } // 实际的AES解密函数 function decrypt(cipherText) { if (!cipherText) return null; try { // 使用提供的WordArray初始化key和iv const key = CryptoJS.lib.WordArray.create([892417589, 858928441, 875967541, 959853362], 16); const iv = CryptoJS.lib.WordArray.create([943076661, 909259829, 875772213, 959591219], 16); // 执行AES解密 const decryptedBytes = CryptoJS.AES.decrypt(cipherText, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); // 按照原网站方式处理解密后的数据 const latin1String = decryptedBytes.toString(CryptoJS.enc.Latin1); return decodeURIComponent(escape(latin1String)); } catch (error) { console.error('解密过程中发生错误:', error); return null; } } // 确保CryptoJS可用(如果未加载则动态加载) if (typeof CryptoJS === 'undefined') { const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js'; script.integrity = 'sha512-E8QSvWZ0eCLGk4km3hxSsNmGWbLtSCSUcewDQPQWZF6pEU8GlT8a5fF32wOl1i8ftdMhssTrF/OhyGWwonTcXA=='; script.crossOrigin = 'anonymous'; document.head.appendChild(script); script.onload = () => { console.log('CryptoJS 加载完成,启动监听'); initXHRInterceptor(); }; script.onerror = () => console.error('CryptoJS 加载失败'); } else { console.log('CryptoJS 已加载,启动监听'); initXHRInterceptor(); } // 初始化XHR拦截器 function initXHRInterceptor() { // 拦截XHR请求 const originalXHR = window.XMLHttpRequest; const originalOpen = originalXHR.prototype.open; const originalSend = originalXHR.prototype.send; XMLHttpRequest.prototype.open = function(method, url) { this._method = method; this._url = url; return originalOpen.apply(this, arguments); }; XMLHttpRequest.prototype.send = function(data) { this._requestData = data; const self = this; const handleResponse = () => { try { // 只处理特定接口 const targetUrl = '/examModular_exam_item.action'; const targetParam = 'getItemList'; if (self._url.includes(targetUrl) && new URL(self._url, location.origin).searchParams.get('req') === targetParam) { console.log('捕获试题数据接口请求'); // 获取响应数据 const responseText = self.responseText; let decryptedData = null; // 尝试解析为JSON try { decryptedData = decryptData(responseText); if (!decryptedData) { console.warn('解密失败,尝试直接解析响应'); decryptedData = JSON.parse(responseText); } console.log('解密后的试题数据:', decryptedData); // 确保只创建一次弹窗 if (!document.getElementById('examDataPopup')) { createPopup(); } // 将数据展示在弹窗中 if (decryptedData) { displayDataInPopup(decryptedData); } else { console.error('解密数据为空'); } } catch (e) { console.warn('响应不是JSON格式,尝试直接解密'); const decryptedStr = decrypt(responseText); decryptedData = decryptedStr ? JSON.parse(decryptedStr) : responseText; } } } catch (e) { console.error('处理响应时出错:', e); } }; // 添加事件监听 this.addEventListener('load', handleResponse); this.addEventListener('error', () => console.error('请求失败:', self._url)); return originalSend.apply(this, arguments); }; console.log('XMLHttpRequest 拦截器已激活'); } })();