Greasy Fork is available in English.

薰匪烤师

讯飞考试,既然都网页端了那还监考个鬼啊…

/* eslint-disable no-multi-spaces */

// ==UserScript==
// @name               薰匪烤师
// @name:zh-CN         薰匪烤师
// @name:en            Fuck Ifly Freedom(FIF).js
// @namespace          Fuck-Ifly-Freedom
// @version            0.3
// @description        讯飞考试,既然都网页端了那还监考个鬼啊…
// @description:zh-CN  讯飞考试,既然都网页端了那还监考个鬼啊…
// @description:en     说实话,我不觉得讯飞考试有外国用户
// @author             PY-DNG
// @license            GPL-license
// @match              http*://assess.fifedu.com/testcenter/examPaper/toExamMain*
// @match              https://assess.fifedu.com/testcenter/login/home
// @icon               https://static.fifedu.com/static/fiftest//images/favicon.ico
// @grant              none
// @run-at             document-start
// ==/UserScript==

(function() {
	// Fuck Ifly Freedom(FIF).js, By PY-DNG
	// Make sure this code is executed before ifly code

	const Angels = {
		setTimeout: window.setTimeout
	}
	const Evils = [{
			target: window,
			name: "topOnFocus",
			value: function topOnFocus() {}
		},{
			target: window,
			name: "topOnBlur",
			value: function topOnBlur() {}
		},{
			target: window,
			name: "setTimeout",
			value: function setTimeout(func, interval) {
				// Filter all evil functions
				const filters = ['focusFlag', 'collectOralInfo', 'switchPageNum']
				for (const filter of filters) {
					if (func.toString().includes(filter)) {return;}
				}
				// Permit others
				const args = Array.from(arguments)
				return Angels.setTimeout.apply(null, args)
			}
		},{
			target: window,
			name: "focusFlag",
			value: true
		},{
			target: window,
			name: "switchPageNum",
			value: -1
		},{
			target: window,
			name: "switchPageIn",
			value: function switchPageIn() {}
		},{
			target: window,
			name: "isLeavingPage",
			value: false
		},{
			target: document,
			name: 'oncontextmenu',
			value: function() {},
			iframe: true
		},{
			target: document,
			name: 'ondragstart',
			value: function() {},
			iframe: true
		},{
			target: document,
			name: 'onselectstart',
			value: function() {},
			iframe: true
		},{
			target: document,
			name: 'onselect',
			value: function() {},
			iframe: true
		},{
			target: document,
			name: 'oncopy',
			value: function() {},
			iframe: true
		},{
			target: document,
			name: 'onpaste',
			value: function() {},
			iframe: true
		},{
			target: document,
			name: 'onbeforecopy',
			value: function() {},
			iframe: true
		},{
			target: document,
			name: 'ontouchmove',
			value: function() {},
			iframe: true
		},{
			target: document,
			name: 'onkeydown',
			value: function() {},
			iframe: true
		},{
			target: document,
			name: 'onkeyup',
			value: function() {},
			iframe: true
		}
	]
	const ITM = new IntervalTaskManager();

	for (const evil of Evils) {
		const target = evil.target;
		const name = evil.name;
		const value = evil.value;
		const iframe = evil.iframe;
		console.log('hooking ' + name);
		try {
			typeof value !== 'function' && Freeze_FIF_Variable(target, name, value);
			ITM.addTask(function() {target[name] = value;});
			if (iframe) {
				ITM.addTask(function() {
					const targets = [document].concat(Array.from(document.querySelectorAll('iframe')).map((iframe) => (target === document ? iframe.contentDocument : iframe.contentWindow)));
					targets.forEach((t) => {t[name] = value;});
				});
			}
		} catch(e) {
			debugger;
			throw e;
		}
		console.log('hooked', target[name], target[name] === value);
	}

	allowSelect();
	ITM.addTask(allowSelect);

	allowpaste();
	ITM.addTask(allowpaste);


	ITM.start();

	function Freeze_FIF_Variable(target, varname, value) {
		defineProperty(target, varname, {
			value: value,
			writable: false
		});
	}

	function allowSelect() {
		const docs = [document].concat(Array.from(document.querySelectorAll('iframe')).map((iframe) => (iframe.contentDocument)))
		docs.forEach((doc) => (Array.from(doc.querySelectorAll('style')).filter((s) => (s.innerHTML.includes('user-select'))).forEach((s) => (s.parentElement.removeChild(s)))));
	}

	function allowpaste() {
		const docs = [document].concat(Array.from(document.querySelectorAll('iframe')).map((iframe) => (iframe.contentDocument)));
		docs.forEach((doc) => (Array.from(doc.querySelectorAll('textarea')).forEach((t) => {t.onpaste = null;})));

	}

	function IntervalTaskManager() {
		const tasks = this.tasks = [];
		this.time = 500;
		this.interval = -1;
		defineProperty(this, 'working', {
			get: () => (this.interval >= 0)
		});

		this.addTask = function(fn) {
			tasks.push(fn);
		}

		this.removeTask = function(fn_idx) {
			const idx = typeof fn_idx === 'number' ? fn_idx : tasks.indexOf(fn_idx)
			tasks.splice(idx, 1)
		}

		this.clearTasks = function() {
			tasks.splice(0, Infinity)
		}

		this.start = function() {
			if (!this.working) {
				this.interval = setInterval(this.do, this.time);
				return true;
			} else {
				return false;
			}
		}

		this.stop = function() {
			if (this.working) {
				clearInterval(this.interval);
				this.interval = -1;
				return true;
			} else {
				return false;
			}
		}

		this.do = function() {
			for (const task of tasks) {
				task();
			}
		}
	}

	function defineProperty(obj, prop, desc) {
		desc.configurable = false;
		desc.enumerable = true;
		Object.defineProperty(obj, prop, desc);
	}
}) ();