/* eslint-disable no-multi-spaces */
// ==UserScript==
// @name 中国大学MOOC反检测
// @name:zh-CN 中国大学MOOC反检测
// @name:en iCourse163 Anti-detect
// @namespace iCourse163-Anti-detect
// @version 0.1
// @description 防止中国大学MOOC页面检测模拟点击类插件/脚本(目前已发现的检测只有检测模拟点击类的)
// @description:zh-CN 防止中国大学MOOC页面检测模拟点击类插件/脚本(目前已发现的检测只有检测模拟点击类的)
// @description:en Prevent plugins(e.g. userscripts) being detected by 1course163 while simulating clicks on webpage
// @author PY-DNG
// @license WTFPL - See https://www.wtfpl.net/
// @match http*://www.icourse163.org/*
// @icon https://pic.jitudisk.com/public/2022/06/04/59e467b286dcb.png
// @grant none
// @run-at document-start
// ==/UserScript==
/**
* Copyright © 2022 PY-DNG <NO EMAIL HERE>
* This work is free. You can redistribute it and/or modify it under the
* terms of the Do What The Fuck You Want To Public License, Version 2,
* as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.
**/
/**
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://www.wtfpl.net/ for more details.
**/
(function(window, document) {
/* Protect.js by PY-DNG */
/* !IMPORTANT! MAKE SURE THIS CODE IS EXECUTED BEFORE WINDOW ONLOAD !IMPORTANT! */
try {
// Unpolluted resources
const iframe = document.createElement('iframe');
iframe.srcdoc = '<html></html>';
iframe.style.position = 'fixed';
iframe.style.width = iframe.style.height = '0';
(document.body ? document.body : document.head).appendChild(iframe);
const UNPOLLUTED = new Proxy({}, {
get: function(target, property, receiver) {
switch (property) {
case 'iframe': return iframe;
default: {
let value = iframe;
for (const prop of property.split(/[\.\/]/)) {
value = value[prop];
}
return value;
}
}
}
});
// Protect addEventListener & removeEventListener
defineProperty(Node.prototype, 'addEventListener', addEventListener);
defineProperty(Node.prototype, 'removeEventListener', UNPOLLUTED['contentWindow.EventTarget.prototype.removeEventListener']);
for (const func of ['createElement', 'createElementNS', 'querySelector', 'querySelectorAll', 'getElementById', 'getElementsByClassName', 'getElementsByName', 'getElementsByTagName', 'getElementsByTagNameNS']) {
hookAPIFunc(func);
}
// Protect root & root-like elements
for (const elm of [document.querySelector('#g-body'), document.documentElement, document, window]) {
const addEventListener = UNPOLLUTED['contentWindow.EventTarget.prototype.addEventListener'];
typeof elm === 'object' && elm !== null && hookElm(elm);
}
function hookAPIFunc(funcName) {
for (const api of ['Document', 'Element']) {
const API = window[api];
const proto = API.prototype;
proto.hasOwnProperty(funcName) && defineProperty(proto, funcName, function() {
let value = UNPOLLUTED['contentWindow.'+api+'.prototype.'+funcName].apply(this, Array.from(arguments));
if (value instanceof NodeList) {
value = Array.prototype.map.call(value, (elm) => (hookElm(elm)));
value.item = (i) => (i < value.length ? value[i] : null);
} else if (value instanceof EventTarget) {
value = hookElm(value);
}
return value;
});
}
}
function hookElm(elm) {
defineProperty(elm, 'addEventListener', addEventListener);
defineProperty(elm, 'removeEventListener', UNPOLLUTED['contentWindow.EventTarget.prototype.removeEventListener']);
return elm;
}
function defineProperty(obj, prop, value) {
// Check repeat
if (obj._protected && obj._protected[prop] && obj[prop].toString() === value.toString()) {
return false;
}
// Define property
define(obj, prop, value, true);
// Prevent repeat
!obj._protected && define(obj, '_protected', {}, false);
define(obj._protected, prop, true, true);
return true;
function define(obj, prop, value, enumerable) {
Object.defineProperty(obj, prop, {
value: value,
writable: false,
configurable: false,
enumerable: enumerable
});
}
}
function addEventListener(type, listener) {
const banlist = ['function(a5){if(', 'function(a6){a6'];
for (const bancode of banlist) {
if (type === 'click' && listener.toString().startsWith(bancode)) {
return;
}
}
return UNPOLLUTED['contentWindow.EventTarget.prototype.addEventListener'].apply(this, Array.from(arguments));
}
function toString(o) {
return UNPOLLUTED['contentWindow.Object.prototype.toString'].call(o);
}
} catch (err) {
throw err;
debugger;
}
}).apply(null, typeof unsafeWindow === 'object' ? [unsafeWindow, unsafeWindow.document] : [window, document]);