Kahoot AntiBot

Remove all bots from a kahoot game.

目前为 2021-01-13 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Kahoot AntiBot
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.14.1
  5. // @icon https://cdn.discordapp.com/icons/641133408205930506/31c023710d468520708d6defb32a89bc.png
  6. // @description Remove all bots from a kahoot game.
  7. // @author theusaf
  8. // @copyright 2018-2021, Daniel Lau (https://github.com/theusaf/kahoot-antibot)
  9. // @match *://play.kahoot.it/*
  10. // @exclude *://play.kahoot.it/v2/assets/*
  11. // @grant none
  12. // @run-at document-start
  13. // @license MIT; https://opensource.org/licenses/MIT
  14. // ==/UserScript==
  15.  
  16. // Notes: changing the questions AND questionIndex stuff works?
  17.  
  18. if(window.fireLoaded || (window.parent && window.parent.page)){
  19. throw "[ANTIBOT] - page is loaded";
  20. }
  21. if(window.localStorage.extraCheck){
  22. console.log("[ANTIBOT] - Detected PIN Checker");
  23. }
  24. if(window.localStorage.kahootThemeScript){
  25. console.log("[ANTIBOT] - Detected KonoSuba Theme");
  26. }
  27. document.write("[ANTIBOT] - Patching Kahoot. Please wait. If this screen stays blank for long periods of time, please force reload or clear your cache.");
  28. window.url = window.location.href;
  29. window.page = new XMLHttpRequest();
  30. window.page.open("GET",window.url);
  31. window.page.send();
  32. window.page.onload = ()=>{
  33. const scriptURL = window.page.response.match(/><\/script><script .*?vendors.*?><\/script>/mg)[0].substr(9).split("src=\"")[1].split("\"")[0],
  34. script2 = window.page.response.match(/\/v2\/assets\/js\/main.*?(?=")/mg)[0];
  35. let originalPage = window.page.response.replace(/><\/script><script .*?vendors.*?><\/script>/mg,"></script>");
  36. originalPage = originalPage.replace(/\/v2\/assets\/js\/main.*?(?=")/mg,"data:text/javascript,");
  37. const script = new XMLHttpRequest();
  38. script.open("GET","https://play.kahoot.it/"+scriptURL);
  39. script.send();
  40. script.onload = ()=>{
  41. const patchedScriptRegex = /\.onMessage=function\([a-z],[a-z]\)\{/mg,
  42. letter1 = script.response.match(patchedScriptRegex)[0].match(/[a-z](?=,)/g)[0],
  43. letter2 = script.response.match(patchedScriptRegex)[0].match(/[a-z](?=\))/g)[0],
  44. patchedScript = script.response.replace(script.response.match(patchedScriptRegex)[0],`.onMessage=function(${letter1},${letter2}){window.globalMessageListener(${letter1},${letter2});`),
  45. code = ()=>{
  46. const windw = window.parent;
  47. window.windw = windw;
  48. // create watermark
  49. const container = document.createElement("div");
  50. container.id = "antibotwtr";
  51. const waterMark = document.createElement("p");
  52. waterMark.innerHTML = "v2.14.1 @theusaf";
  53. const botText = document.createElement("p");
  54. botText.innerHTML = "0";
  55. botText.id = "killcount";
  56. const menu = document.createElement("details");
  57. menu.innerHTML = `<summary>config</summary>
  58. <div id="antibot-settings">
  59. <!-- Timeout -->
  60. <div>
  61. <input type="checkbox" id="antibot.config.timeout"></input>
  62. <label id="antibot.config.timeoutlbl" onclick="windw.specialData.config.timeout = !windw.specialData.config.timeout;if(!windw.localStorage.antibotConfig){windw.localStorage.antibotConfig = JSON.stringify({});}const a = JSON.parse(windw.localStorage.antibotConfig);a.timeout = windw.specialData.config.timeout;windw.localStorage.antibotConfig = JSON.stringify(a);" for="antibot.config.timeout" title="Blocks answers that are sent before 0.5 seconds after the question starts">Min Answer Timeout</label>
  63. </div>
  64. <!-- Random Names -->
  65. <div>
  66. <input type="checkbox" id="antibot.config.looksRandom" checked="checked"></input>
  67. <label id="antibot.config.lookrandlbl" onclick="windw.specialData.config.looksRandom = !windw.specialData.config.looksRandom;if(!windw.localStorage.antibotConfig){windw.localStorage.antibotConfig = JSON.stringify({});}const a = JSON.parse(windw.localStorage.antibotConfig);a.looksRandom = windw.specialData.config.looksRandom;windw.localStorage.antibotConfig = JSON.stringify(a);" for="antibot.config.looksRandom" title="Blocks names that seem 'random', such as 'OmEGaboOt'">Block Random Names</label>
  68. </div>
  69. <!-- Blocking Format 1 -->
  70. <div>
  71. <input type="checkbox" id="antibot.config.blockformat1" checked="checked"></input>
  72. <label id="antibot.config.blockformat1lbl" onclick="windw.specialData.config.banFormat1 = !windw.specialData.config.banFormat1;if(!windw.localStorage.antibotConfig){windw.localStorage.antibotConfig = JSON.stringify({});}const a = JSON.parse(windw.localStorage.antibotConfig);a.banFormat1 = windw.specialData.config.banFormat1;windw.localStorage.antibotConfig = JSON.stringify(a);" for="antibot.config.blockformat1" title="Blocks names using the format [First][random char][Last]">Block format First[._-,etc]Last</label>
  73. </div>
  74. <!-- Blocking kahootflood.weebly.com -->
  75. <div>
  76. <input type="checkbox" id="antibot.config.blockservice1"></input>
  77. <label onclick="windw.specialData.config.blockservice1 = !windw.specialData.config.blockservice1;if(!windw.localStorage.antibotConfig){windw.localStorage.antibotConfig = JSON.stringify({});}const a = JSON.parse(windw.localStorage.antibotConfig);a.blockservice1 = windw.specialData.config.blockservice1;windw.localStorage.antibotConfig = JSON.stringify(a);" for="antibot.config.blockservice1" title="A special filter focused on kahootflood.weebly.com">Block kahootflood.weebly.com</label>
  78. </div>
  79. <!-- Block Numbers -->
  80. <div>
  81. <input type="checkbox" id="antibot.config.blocknum"></input>
  82. <label onclick="windw.specialData.config.blocknum = !windw.specialData.config.blocknum;if(!windw.localStorage.antibotConfig){windw.localStorage.antibotConfig = JSON.stringify({});}const a = JSON.parse(windw.localStorage.antibotConfig);a.blocknum = windw.specialData.config.blocknum;windw.localStorage.antibotConfig = JSON.stringify(a);" for="antibot.config.blocknum" title="Marks names with numbers as suspicious. If multiple players join with numbers in their name in a short amount of time, they will be banned.">Block Numbers</label>
  83. </div>
  84. <!-- Block Non-Ascii -->
  85. <div>
  86. <input type="checkbox" id="antibot.config.forceascii"></input>
  87. <label onclick="windw.specialData.config.forceascii = !windw.specialData.config.forceascii;if(!windw.localStorage.antibotConfig){windw.localStorage.antibotConfig = JSON.stringify({});}const a = JSON.parse(windw.localStorage.antibotConfig);a.forceascii = windw.specialData.config.forceascii;windw.localStorage.antibotConfig = JSON.stringify(a);" for="antibot.config.forceascii" title="Marks names with non-alphanumeric characters as suspicious and bans them if multiple join.">Force Alphanumeric</label>
  88. </div>
  89. <!-- Additional Question Time -->
  90. <div>
  91. <label class="antibot-input" for="antibot.config.teamtimeout" title="Add extra seconds to the question.">Additional Question Time</label>
  92. <input type="number" step="1" value="0" id="antibot.config.teamtimeout" onchange="windw.specialData.config.additionalQuestionTime = Number(document.getElementById('antibot.config.teamtimeout').value);if(!windw.localStorage.antibotConfig){windw.localStorage.antibotConfig = JSON.stringify({});}const a = JSON.parse(windw.localStorage.antibotConfig);a.teamtime = windw.specialData.config.additionalQuestionTime;windw.localStorage.antibotConfig = JSON.stringify(a);">
  93. </div>
  94. <!-- Percent -->
  95. <div>
  96. <label class="antibot-input" for="antibot.config.percent" title="Specify the match percentage.">Match Percent</label>
  97. <input type="number" step="0.1" value="0.6" id="antibot.config.percent" onchange="windw.specialData.config.percent = Number(document.getElementById('antibot.config.percent').value);if(!windw.localStorage.antibotConfig){windw.localStorage.antibotConfig = JSON.stringify({});}const a = JSON.parse(windw.localStorage.antibotConfig);a.percent = windw.specialData.config.percent;windw.localStorage.antibotConfig = JSON.stringify(a);">
  98. </div>
  99. <!-- DDOS -->
  100. <div>
  101. <label class="antibot-input" for="antibot.config.ddos" title="Specify the number of bots/minute to lock the game. Set it to 0 to disable.">Auto Lock Threshold</label>
  102. <input type="number" step="1" value="0" id="antibot.config.ddos" onchange="windw.specialData.config.ddos = Number(document.getElementById('antibot.config.ddos').value);if(!windw.localStorage.antibotConfig){windw.localStorage.antibotConfig = JSON.stringify({});}const a = JSON.parse(windw.localStorage.antibotConfig);a.ddos = windw.specialData.config.ddos;windw.localStorage.antibotConfig = JSON.stringify(a);">
  103. </div>
  104. <!-- Auto-Start-Lock -->
  105. <div>
  106. <label class="antibot-input" for="antibot.config.start_lock" title="Specify the maximum time in seconds for a lobby to stay open after a player joins. Setting this to 0 will disable it.">Lobby Auto-Start Time</label>
  107. <input type="number" step="1" value="0" id="antibot.config.start_lock" onchange="windw.specialData.config.start_lock = Number(document.getElementById('antibot.config.start_lock').value);if(!windw.localStorage.antibotConfig){windw.localStorage.antibotConfig = JSON.stringify({});}const a = JSON.parse(windw.localStorage.antibotConfig);a.start_lock = windw.specialData.config.start_lock;windw.localStorage.antibotConfig = JSON.stringify(a);">
  108. </div>
  109. <!-- Toggling Streak Bonus -->
  110. <div>
  111. <input type="checkbox" id="antibot.config.streakBonus" onchange="windw.specialData.config.streakBonus = Number(document.getElementById('antibot.config.streakBonus').checked ? 1 : 2);if(!windw.localStorage.antibotConfig){windw.localStorage.antibotConfig = JSON.stringify({});}const a = JSON.parse(windw.localStorage.antibotConfig);a.streakBonus = windw.specialData.config.streakBonus;localStorage.antibotConfig = JSON.stringify(a);alert('When modifying this option, reload the page for it to take effect')">
  112. <label for="antibot.config.streakBonus" title="Toggle the Streak Bonus.">Toggle Streak Bonus</label>
  113. </div>
  114. <!-- Show Antibot Counters -->
  115. <div>
  116. <input type="checkbox" id="antibot.config.counters" onchange="windw.specialData.config.counters = document.getElementById('antibot.config.counters').checked;if(!windw.localStorage.antibotConfig){windw.localStorage.antibotConfig = JSON.stringify({});}const a = JSON.parse(windw.localStorage.antibotConfig);a.counters = windw.specialData.config.counters;localStorage.antibotConfig = JSON.stringify(a);">
  117. <label for="antibot.config.counters" title="Shows Antibot Countdowns (Lobby Auto-Start/Auto-Lock)">Show Antibot Timers</label>
  118. </div>
  119. <!-- Counter cheats -->
  120. <div>
  121. <input type="checkbox" id="antibot.config.counterCheats" onchange="windw.specialData.config.counterCheats = document.getElementById('antibot.config.counterCheats').checked;
  122. if(!windw.localStorage.antibotConfig){
  123. windw.localStorage.antibotConfig = JSON.stringify({});
  124. }
  125. const a = JSON.parse(windw.localStorage.antibotConfig);
  126. a.counterCheats = windw.specialData.config.counterCheats;
  127. localStorage.antibotConfig = JSON.stringify(a);
  128. if(a.counterCheats){
  129. // enable cheats
  130. alert('Changes may only take effect upon reload.');
  131. }else{
  132. // disable anti-cheat
  133. const q = windw.specialData.globalQuizData.questions;
  134. if(q[q.length - 1].isAntibotQuestion){
  135. q.splice(-1,1);
  136. delete windw.specialData.kahootCore.game.navigation.questionIndexMap[q.length];
  137. }
  138. }">
  139. <label for="antibot.config.counterCheats" title="Adds an additional 20 second question at the end to counter cheats. Note: Changing this mid-game may break the game.">Counter Kahoot Cheats</label>
  140. </div>
  141. <!-- CAPTCHA -->
  142. <div>
  143. <input type="checkbox" id="antibot.config.enableCAPTCHA" onchange="windw.specialData.config.enableCAPTCHA = document.getElementById('antibot.config.enableCAPTCHA').checked;
  144. if(!windw.localStorage.antibotConfig){
  145. windw.localStorage.antibotConfig = JSON.stringify({});
  146. }
  147. const a = JSON.parse(windw.localStorage.antibotConfig);
  148. a.enableCAPTCHA = windw.specialData.config.enableCAPTCHA;
  149. localStorage.antibotConfig = JSON.stringify(a);
  150. if(a.enableCAPTCHA){
  151. // enable captcha
  152. alert('Changes may only take effect upon reload.');
  153. }else{
  154. // disable captcha
  155. const q = windw.specialData.globalQuizData.questions;
  156. if(q[0].isAntibotQuestion){
  157. q.splice(0,1);
  158. delete windw.specialData.kahootCore.game.navigation.questionIndexMap[q.length];
  159. }
  160. }">
  161. <label for="antibot.config.enableCAPTCHA" title="Adds a 30 second poll at the start of the quiz. If players don't answer it correctly, they get banned. Note: Changing this mid-game may break the game.">Enable CAPTCHA</label>
  162. </div>
  163. </div>`;
  164. const counters = document.createElement("div");
  165. counters.id = "antibot-counters";
  166. const styles = document.createElement("style");
  167. styles.type = "text/css";
  168. styles.innerHTML = `#antibotwtr{
  169. position: fixed;
  170. bottom: 100px;
  171. right: 100px;
  172. font-size: 1rem;
  173. opacity: 0.4;
  174. transition: opacity 0.4s;
  175. z-index: 5000;
  176. background: white;
  177. text-align: center;
  178. border-radius: 0.5rem;
  179. }
  180. #antibotwtr summary{
  181. text-align: left;
  182. }
  183. #antibotwtr:hover{
  184. opacity: 1;
  185. }
  186. #antibotwtr p{
  187. display: inline-block;
  188. }
  189. #antibotwtr p:first-child{
  190. font-weight: 600;
  191. }
  192. #killcount{
  193. margin-left: 0.25rem;
  194. background: black;
  195. border-radius: 0.5rem;
  196. color: white;
  197. }
  198. #antibotwtr details{
  199. background: grey;
  200. }
  201. #antibotwtr input[type="checkbox"]{
  202. display: none;
  203. }
  204. #antibotwtr label{
  205. color: black;
  206. font-weight: 600;
  207. display: block;
  208. background: #c60929;
  209. border-radius: 0.5rem;
  210. height: 100%;
  211. word-break: break-word;
  212. }
  213. #antibotwtr .antibot-input{
  214. height: calc(100% - 1.5rem);
  215. background: #864cbf;
  216. color: white;
  217. }
  218. #antibotwtr input{
  219. position: absolute;
  220. bottom: 0;
  221. left: 0;
  222. width: 100%;
  223. height: 1rem;
  224. border-radius: 0.25rem;
  225. border: solid 1px black;
  226. }
  227. #antibotwtr input:checked+label{
  228. background: #26890c;
  229. }
  230. #antibot-settings{
  231. display: flex;
  232. flex-wrap: wrap;
  233. max-width: 25rem;
  234. max-height: 24rem;
  235. overflow: auto;
  236. }
  237. #antibot-settings > div{
  238. flex: 1;
  239. max-width: 33%;
  240. min-width: 33%;
  241. min-height: 6rem;
  242. box-sizing: border-box;
  243. position: relative;
  244. border: solid 0.5rem transparent;
  245. }
  246. #antibot-counters{
  247. position: absolute;
  248. right: 10rem;
  249. top: 11rem;
  250. font-size: 1.5rem;
  251. font-weight: 700;
  252. color: white;
  253. pointer-events: none;
  254. }
  255. #antibot-counters div{
  256. background: rgba(0,0,0,0.5);
  257. padding: 0.5rem;
  258. border-radius: 0.5rem;
  259. margin-bottom: 0.5rem;
  260. }
  261. .antibot-count-num{
  262. display: block;
  263. text-align: center;
  264. }
  265. .antibot-count-desc{
  266. text-align: center;
  267. font-size: 1.25rem;
  268. display: block;
  269. }`;
  270. container.append(waterMark,botText,menu);
  271. setTimeout(function(){
  272. if(document.body.innerText.split("\n").length < 8){ // assume broken. (just the water mark)
  273. const temp = document.createElement("template");
  274. temp.innerHTML = `<div id="antibot-broken-page" style="color: red; position: fixed; left: 0; top: 0; font-size: 1.25rem;line-height:1.75rem">
  275. <h2>[ANTIBOT] - Detected broken page. This message may appear due to slow internet. It will dissapear once the page loads. If the page doesn't load, try one of the following:</h2>
  276. <hr/>
  277. <h2>Reload the page</h2>
  278. <h2>Go back to <a href="https://create.kahoot.it/details/${location.search.split("quizId=")[1].split("&")[0]}">the kahoot launch screen</a>.</h2><br/>
  279. <h2>Clear the cache of this page and then reload.</h2><br/>
  280. <h2>Disable Kahoot AntiBot, reload the page, then re-enable Kahoot Antibot and reload the page again</h2>
  281. </div>`;
  282. document.body.append(temp.content.cloneNode(true));
  283. const RemoveBroke = setInterval(()=>{
  284. if(document.body.innerText.split("\n").length >= 20){
  285. clearInterval(RemoveBroke);
  286. document.getElementById("antibot-broken-page").outerHTML = "";
  287. }
  288. },1000);
  289. }
  290. },2000);
  291. document.body.append(container,styles,counters);
  292. const killcount = document.getElementById("killcount");
  293. windw.isUsingNamerator = false;
  294. windw.cachedUsernames = [];
  295. windw.confirmedPlayers = [];
  296. windw.cachedData = {};
  297. windw.loggedPlayers = {};
  298. windw.specialData = {
  299. extraQuestionSetup: (quiz)=>{
  300. if(windw.specialData.config.counterCheats){
  301. const len = quiz.questions.push({
  302. question:"[ANTIBOT] - This poll is for countering Kahoot cheating sites.",
  303. time:20000,
  304. type:"survey",
  305. isAntibotQuestion:true,
  306. choices:[{answer:"OK",correct:true}]
  307. });
  308. // windw.specialData.kahootCore.game.navigation.questionIndexMap[len - 1] = len - 1;
  309. }
  310. if(windw.specialData.config.enableCAPTCHA){
  311. const answers = ["red","blue","yellow","green"],
  312. images = [
  313. "https://cdn.discordapp.com/attachments/775828441127714837/798671584520568852/red.png",
  314. "https://cdn.discordapp.com/attachments/775828441127714837/798671580778594344/blue.png",
  315. "https://cdn.discordapp.com/attachments/775828441127714837/798671583178522685/yellow.png",
  316. "https://cdn.discordapp.com/attachments/775828441127714837/798671581962436619/green.png"
  317. ],
  318. imageIndex = Math.floor(Math.random() * answers.length);
  319. quiz.questions.splice(0,0,{
  320. question: `[ANTIBOT] - CAPTCHA: Please select ${answers[imageIndex]}`,
  321. time: 30000,
  322. type: "survey",
  323. isAntibotQuestion: true,
  324. AntibotCaptchaCorrectIndex: imageIndex,
  325. choices:[{answer:"OK"},{answer:"OK"},{answer:"OK"},{answer:"OK"}],
  326. image: images[imageIndex]
  327. });
  328. // windw.specialData.kahootCore.game.navigation.questionIndexMap[quiz.length - 1] = quiz.length - 1;
  329. }
  330. },
  331. startTime: 0,
  332. lastFakeLogin: 0,
  333. lastFakeUserID: 0,
  334. lastFakeUserName: "",
  335. config:{
  336. timeout: false,
  337. blocknum: false,
  338. looksRandom: true,
  339. banFormat1: true,
  340. additionalQuestionTime: null,
  341. percent: 0.6,
  342. streakBonus: 2,
  343. ddos: 0,
  344. start_lock: 0,
  345. counters: false,
  346. forceascii: false,
  347. blockservice1: false,
  348. enableCAPTCHA: false
  349. },
  350. inLobby: true,
  351. lobbyLoadTime: 0,
  352. lockInterval: null,
  353. kahootCore: null,
  354. globalFuncs: null,
  355. waitCounterCheats: null,
  356. waitEnableCaptcha: null,
  357. CAPTCHA_IDS: null
  358. };
  359. // loading localStorage info
  360. if(windw.localStorage.antibotConfig){
  361. const a = JSON.parse(windw.localStorage.antibotConfig);
  362. if(a.timeout){
  363. const t = document.getElementById("antibot.config.timeoutlbl");
  364. if(t){
  365. t.click();
  366. }
  367. }
  368. if(a.blocknum){
  369. const t = document.getElementById("antibot.config.blocknum");
  370. t.checked = true;
  371. windw.specialData.config.blocknum = true;
  372. }
  373. if(!a.looksRandom){
  374. const t = document.getElementById("antibot.config.lookrandlbl");
  375. if(t){
  376. t.click();
  377. }
  378. }
  379. if(a.teamtime){
  380. document.getElementById("antibot.config.teamtimeout").value = Number(a.teamtime);
  381. windw.specialData.config.additionalQuestionTime = Number(a.teamtime);
  382. }
  383. if(a.percent){
  384. document.getElementById("antibot.config.percent").value = Number(a.percent);
  385. windw.specialData.config.percent = Number(a.percent);
  386. }
  387. if(!a.banFormat1){
  388. document.getElementById("antibot.config.blockformat1").checked = false;
  389. windw.specialData.config.banFormat1 = false;
  390. }
  391. if(a.streakBonus == 1){
  392. document.getElementById("antibot.config.streakBonus").checked = true;
  393. windw.specialData.config.streakBonus = 1;
  394. }
  395. if(a.ddos){
  396. document.getElementById("antibot.config.ddos").value = +a.ddos;
  397. windw.specialData.config.ddos = +a.ddos;
  398. }
  399. if(a.start_lock){
  400. document.getElementById("antibot.config.start_lock").value = +a.start_lock;
  401. windw.specialData.config.start_lock = +a.start_lock;
  402. }
  403. if(a.counters){
  404. document.getElementById("antibot.config.counters").checked = true;
  405. windw.specialData.config.counters = true;
  406. }
  407. if(a.forceascii){
  408. document.getElementById("antibot.config.forceascii").checked = true;
  409. windw.specialData.config.forceascii = true;
  410. }
  411. if(a.blockservice1){
  412. document.getElementById("antibot.config.blockservice1").checked = true;
  413. windw.specialData.config.blockservice1 = true;
  414. }
  415. if(a.counterCheats){
  416. document.getElementById("antibot.config.counterCheats").checked = true;
  417. windw.specialData.config.counterCheats = true;
  418. }
  419. if(a.enableCAPTCHA){
  420. document.getElementById("antibot.config.enableCAPTCHA").checked = true;
  421. windw.specialData.config.enableCAPTCHA = true;
  422. }
  423. }
  424. let messageId = 0,
  425. clientId = null,
  426. pin = null;
  427. // for names like KaHOotSmaSH
  428. function looksRandom(name){
  429. // Assumes player names have either all caps, no caps, or up to 3 capital letters
  430. return !/(^(([^A-Z\n]*)?[A-Z]?([^A-Z\n]*)?){0,3}$)|^([A-Z]*)$/.test(name);
  431. }
  432. // for names like AmazingRobot32
  433. // also matches other somewhat suspicious names
  434. function isFakeValid(name){
  435. if(windw.specialData.config.blocknum && /\d/.test(name)){
  436. return true;
  437. }
  438. if(windw.specialData.config.forceascii && /[^\d\s\w_-]/.test(name)){
  439. return true;
  440. }
  441. return /(^([A-Z][a-z]+){2,3}\d{1,2}$)|(^([A-Z][^A-Z\n]+?)+?(\d[a-z]+\d*?)$)|(^[a-zA-Z]+\d{4,}$)/.test(name);
  442. }
  443. function similarity(s1, s2) {
  444. // remove numbers from name if name is not only a number
  445. if(isNaN(s1) && typeof(s1) !== "object" && !windw.isUsingNamerator){
  446. s1 = s1.replace(/[0-9]/mg,"");
  447. }
  448. if(isNaN(s2) && typeof(s2) !== "object" && !windw.isUsingNamerator){
  449. s2 = s2.replace(/[0-9]/mg,"");
  450. }
  451. if(!s2){
  452. return 0;
  453. }
  454. // if is a number of the same length
  455. if(s1){
  456. if(!isNaN(s2) && !isNaN(s1) && s1.length == s2.length){
  457. return 1;
  458. }
  459. }
  460. // apply namerator rules
  461. if(windw.isUsingNamerator){
  462. if(!/^([A-Z][a-z]+){2,3}$/.test(s2)){
  463. return -1;
  464. }
  465. }
  466. if(!s1){
  467. return;
  468. }
  469. // ignore case
  470. s1 = s1.toLowerCase();
  471. s2 = s2.toLowerCase();
  472. let longer = s1,
  473. shorter = s2;
  474. // begin math to determine similarity
  475. if (s1.length < s2.length) {
  476. longer = s2;
  477. shorter = s1;
  478. }
  479. const longerLength = longer.length;
  480. if (longerLength == 0) {
  481. return 1.0;
  482. }
  483. return (longerLength - editDistance(longer, shorter)) / parseFloat(longerLength);
  484. }
  485. function editDistance(s1, s2) {
  486. s1 = s1.toLowerCase();
  487. s2 = s2.toLowerCase();
  488.  
  489. const costs = new Array();
  490. for (let i = 0; i <= s1.length; i++) {
  491. let lastValue = i;
  492. for (let j = 0; j <= s2.length; j++) {
  493. if (i == 0){
  494. costs[j] = j;
  495. }
  496. else {
  497. if (j > 0) {
  498. let newValue = costs[j - 1];
  499. if (s1.charAt(i - 1) != s2.charAt(j - 1)){
  500. newValue = Math.min(Math.min(newValue,lastValue),costs[j]) + 1;
  501. }
  502. costs[j - 1] = lastValue;
  503. lastValue = newValue;
  504. }
  505. }
  506. }
  507. if (i > 0){
  508. costs[s2.length] = lastValue;
  509. }
  510. }
  511. return costs[s2.length];
  512. }
  513. function setup(){
  514. const launch_button =document.querySelectorAll("[data-functional-selector=\"launch-button\"]")[0];
  515. if(launch_button){
  516. console.warn("[ANTIBOT] - launch button found!");
  517. }else{
  518. setTimeout(setup,1000);
  519. }
  520. }
  521. setup();
  522. function clickName(name){
  523. const names = document.querySelectorAll("[data-functional-selector=player-name]");
  524. names.forEach(o=>{
  525. if(o.innerText == name){
  526. return o.click();
  527. }
  528. });
  529. }
  530. function createKickPacket(id){
  531. messageId++;
  532. return [{
  533. channel: "/service/player",
  534. clientId: clientId,
  535. id: String(Number(messageId)),
  536. data: {
  537. cid: String(id),
  538. content: JSON.stringify({
  539. kickCode: 1,
  540. quizType: "quiz"
  541. }),
  542. gameid: pin,
  543. host: "play.kahoot.it",
  544. id: 10,
  545. type: "message"
  546. },
  547. ext: {}
  548. }];
  549. }
  550. function determineEvil(player,socket){
  551. if(windw.cachedUsernames.length == 0){
  552. if(similarity(null,player.name) == -1){
  553. const packet = createKickPacket(player.cid);
  554. socket.send(JSON.stringify(packet));
  555. console.warn(`[ANTIBOT] - Bot ${player.name} has been banished`);
  556. killcount.innerHTML = +killcount.innerHTML + 1;
  557. delete windw.cachedData[player.cid];
  558. throw "[ANTIBOT] - Bot banned. Dont add";
  559. }
  560. windw.cachedUsernames.push({name: player.name, id:player.cid, time: 10, banned: false});
  561. windw.loggedPlayers[player.cid] = true;
  562. }else{
  563. let removed = false;
  564. if(similarity(null,player.name) == -1){
  565. removed = true;
  566. const packet1 = createKickPacket(player.cid);
  567. socket.send(JSON.stringify(packet1));
  568. console.warn(`[ANTIBOT] - Bot ${player.name} has been banished`);
  569. killcount.innerHTML = +killcount.innerHTML + 1;
  570. delete windw.cachedData[player.cid];
  571. throw "[ANTIBOT] - Bot banned. Dont add";
  572. }
  573. for(const i in windw.cachedUsernames){
  574. if(windw.confirmedPlayers.includes(windw.cachedUsernames[i].name)){
  575. continue;
  576. }
  577. if(similarity(windw.cachedUsernames[i].name,player.name) >= windw.specialData.config.percent){
  578. removed = true;
  579. const packet1 = createKickPacket(player.cid);
  580. socket.send(JSON.stringify(packet1));
  581. if(!windw.cachedUsernames[i].banned){
  582. const packet2 =createKickPacket(windw.cachedUsernames[i].id);
  583. windw.cachedUsernames[i].banned = true;
  584. socket.send(JSON.stringify(packet2));
  585. clickName(windw.cachedUsernames[i].name);
  586. killcount.innerHTML = +killcount.innerHTML + 1;
  587. }
  588. windw.cachedUsernames[i].time = 10;
  589. console.warn(`[ANTIBOT] - Bots ${player.name} and ${windw.cachedUsernames[i].name} have been banished`);
  590. killcount.innerHTML = +killcount.innerHTML + 1;
  591. delete windw.cachedData[player.cid];
  592. delete windw.cachedData[windw.cachedUsernames[i].id];
  593. throw "[ANTIBOT] - Bot banned. Dont add";
  594. }
  595. }
  596. if(!removed){
  597. windw.cachedUsernames.push({name: player.name,id: player.cid, time: 10, banned: false});
  598. windw.loggedPlayers[player.cid] = true;
  599. }
  600. }
  601. }
  602. function specialBotDetector(type,data,socket){
  603. switch (type) {
  604. case "joined":
  605. // if looks random
  606. if(windw.specialData.config.looksRandom){
  607. if(looksRandom(data.name)){
  608. const packet = createKickPacket(data.cid);
  609. socket.send(JSON.stringify(packet));
  610. killcount.innerHTML = +killcount.innerHTML + 1;
  611. windw.cachedUsernames.forEach(o=>{
  612. if(o.id == data.cid){
  613. o.banned = true;
  614. o.time = 10;
  615. return;
  616. }
  617. });
  618. throw `[ANTIBOT] - Bot ${data.name} banned; name too random.`;
  619. }
  620. }
  621. // if ban format 1 is enabled
  622. if(windw.specialData.config.banFormat1){
  623. if(/[a-z0-9]+[^a-z0-9\s][a-z0-9]+/gi.test(data.name)){
  624. const packet = createKickPacket(data.cid);
  625. socket.send(JSON.stringify(packet));
  626. killcount.innerHTML = +killcount.innerHTML + 1;
  627. windw.cachedUsernames.forEach(o=>{
  628. if(o.id == data.cid){
  629. o.banned = true;
  630. o.time = 10;
  631. return;
  632. }
  633. });
  634. throw `[ANTIBOT] - Bot ${data.name} banned; Name matches format [F][R][L].`;
  635. }
  636. }
  637. // special filters for kahootflood.weebly.com
  638. if(windw.specialData.config.blockservice1){
  639. if(data.name.replace(/[ᗩᗷᑕᗪEᖴGᕼIᒍKᒪᗰᑎOᑭᑫᖇᔕTᑌᐯᗯ᙭Yᘔ]/g,"").length / data.name.length < 0.5){
  640. const packet = createKickPacket(data.cid);
  641. socket.send(JSON.stringify(packet));
  642. killcount.innerHTML = +killcount.innerHTML + 1;
  643. windw.cachedUsernames.forEach(o=>{
  644. if(o.id == data.cid){
  645. o.banned = true;
  646. o.time = 10;
  647. return;
  648. }
  649. });
  650. throw `[ANTIBOT] - Bot ${data.name} banned; likely from kahootflood.weebly.com.`;
  651. }
  652. }
  653. if(!windw.cachedData[data.cid] && !isNaN(data.cid) && Object.keys(data).length <= 5 && data.name.length < 16){ //if the id has not been cached yet or is an invalid id, and they are not a bot :p
  654. windw.cachedData[data.cid] = {
  655. tries: 0,
  656. loginTime: Date.now()
  657. };
  658. }else{
  659. if(windw.cachedData[data.cid]){ // now allowing reconnection
  660. return;
  661. }
  662. const packet = createKickPacket(data.cid);
  663. socket.send(JSON.stringify(packet));
  664. console.warn(`[ANTIBOT] - Bot ${data.name} has been banished - invalid packet/name`);
  665. windw.cachedUsernames.forEach(o=>{
  666. if(o.id == data.cid){
  667. o.banned = true;
  668. o.time = 10;
  669. return;
  670. }
  671. });
  672. killcount.innerHTML = +killcount.innerHTML + 1;
  673. delete windw.cachedData[data.cid];
  674. throw "[ANTIBOT] - Bot banned. Dont add";
  675. }
  676. if(!windw.isUsingNamerator){
  677. if(isFakeValid(data.name)){
  678. if(Date.now() - windw.specialData.lastFakeLogin < 5000){
  679. if(windw.cachedData[windw.specialData.lastFakeUserID]){ // to get the first guy
  680. const packet = createKickPacket(windw.specialData.lastFakeUserID);
  681. socket.send(JSON.stringify(packet));
  682. clickName(windw.specialData.lastFakeUserName);
  683. delete windw.cachedData[windw.specialData.lastFakeUserID]; windw.cachedUsernames.forEach(o=>{
  684. if(o.id == windw.specialData.lastFakeUserID){
  685. o.banned = true;
  686. o.time = 10;
  687. return;
  688. }
  689. });
  690. }
  691. const packet = createKickPacket(data.cid);
  692. socket.send(JSON.stringify(packet));
  693. delete windw.cachedData[data.cid];
  694. windw.cachedUsernames.forEach(o=>{
  695. if(o.id == data.cid){
  696. o.banned = true;
  697. return;
  698. }
  699. });
  700. killcount.innerHTML = +killcount.innerHTML + 1;
  701. windw.specialData.lastFakeLogin = Date.now();
  702. windw.specialData.lastFakeUserID = data.cid;
  703. windw.specialData.lastFakeUserName = data.name;
  704. throw `[ANTIBOT] - Banned bot ${data.name}; their name is suspicious, likely a bot.`;
  705. }
  706. windw.specialData.lastFakeLogin = Date.now();
  707. windw.specialData.lastFakeUserID = data.cid;
  708. windw.specialData.lastFakeUserName = data.name;
  709. }
  710. }
  711. break;
  712. }
  713. }
  714. function teamBotDetector(team,cid,socket){
  715. let kick = false;
  716. if(team.length == 0 || team.indexOf("") != -1 || team.indexOf("Player 1") != -1 || team.join("") === "Youjustgotbotted" /* kahootflood.weebly.com */){
  717. kick = true;
  718. }
  719. if(kick){
  720. const packet = createKickPacket(cid);
  721. socket.send(JSON.stringify(packet));
  722. killcount.innerHTML = +killcount.innerHTML + 1;
  723. let name = "";
  724. delete windw.cachedData[cid];
  725. windw.cachedUsernames.forEach(o=>{
  726. name = o.name;
  727. if(o.id == cid){
  728. o.banned = true;
  729. o.time = 10;
  730. return;
  731. }
  732. });
  733. throw `[ANTIBOT] - Bot ${name} banned; invalid team members.`;
  734. }
  735. }
  736. // Cache Manager Timer
  737. setInterval(function(){
  738. for(const i in windw.cachedUsernames){
  739. if(windw.cachedUsernames[i].time <= 0 && !windw.cachedUsernames[i].banned && !windw.confirmedPlayers.includes(windw.cachedUsernames[i].name)){
  740. windw.confirmedPlayers.push(windw.cachedUsernames[i].name);
  741. continue;
  742. }
  743. if(windw.cachedUsernames[i].time <= -20){
  744. windw.cachedUsernames.splice(i,1);
  745. continue;
  746. }
  747. windw.cachedUsernames[i].time--;
  748. }
  749. },1000);
  750. // 2 Factor Auth Timer
  751. setInterval(()=>{
  752. for(const i in windw.cachedData){
  753. windw.cachedData[i].tries = 0;
  754. }
  755. },10000);
  756. windw.sendHandler = function(data,e){
  757. data = JSON.parse(data)[0];
  758. if(data.data){
  759. if(!data.data.id){
  760. return;
  761. }
  762. switch (data.data.id) {
  763. case 2:
  764. // question start
  765. windw.specialData.startTime = Date.now();
  766. windw.specialData.CAPTCHA_IDS = new Set;
  767. break;
  768. case 5:
  769. // restart
  770. windw.specialData.inLobby = true;
  771. windw.specialData.lobbyLoadTime = 0;
  772. break;
  773. case 10:
  774. if(data.data.content === "{}"){
  775. windw.specialData.inLobby = true;
  776. windw.specialData.lobbyLoadTime = 0;
  777. }
  778. break;
  779. case 9:
  780. // start
  781. windw.specialData.inLobby = false;
  782. if(windw.specialData.StartLockElem){
  783. clearInterval(windw.specialData.StartLockInterval);
  784. windw.specialData.StartLockElem.outerHTML = "";
  785. windw.specialData.StartLockElem = null;
  786. }
  787. break;
  788. case 4:
  789. // question end
  790. if(windw.specialData.kahootCore.game.navigation.currentGameBlockIndex === 0
  791. && windw.specialData.globalQuizData.questions[0].isAntibotQuestion){
  792. // boot all who did not answer
  793. const controllers = windw.specialData.kahootCore.game.core.controllers,
  794. answeredControllers = windw.specialData.CAPTCHA_IDS;
  795. for(const id in controllers){
  796. if(!answeredControllers.has(id)){
  797. const pack = createKickPacket(id);
  798. e.webSocket.send(JSON.stringify(pack));
  799. killcount.innerHTML = +killcount.innerHTML + 1;
  800. console.error("[ANTIBOT] - Bot banned. Did not answer the CAPTCHA.");
  801. delete windw.cachedData[data.data.cid];
  802. delete controllers[id];
  803. }
  804. }
  805. }
  806. break;
  807. }
  808. }
  809. };
  810. let ExtraCheck2 = function(){};
  811. try{
  812. if(windw.localStorage.extraCheck2){
  813. ExtraCheck2 = new Function("return " + windw.localStorage.extraCheck2)();
  814. }
  815. }catch(e){/* Likely doesn't exist */}
  816. let oldamount = 0,
  817. locked = false;
  818. setInterval(()=>{
  819. oldamount = +killcount.innerHTML;
  820. },20e3);
  821. window.globalMessageListener = function(e,t){
  822. try{ExtraCheck2(e,t);}catch(e){console.error("[ANTIBOT] - Execution of PIN-CHECKER Failed: " + e);}
  823. windw.e = e;
  824. if(!windw.e.webSocket.oldSend){
  825. windw.e.webSocket.oldSend = windw.e.webSocket.send;
  826. windw.e.webSocket.send = function(data){
  827. windw.sendHandler(data,e);
  828. windw.e.webSocket.oldSend(data);
  829. };
  830. }
  831. try{pin = windw.specialData.kahootCore.game.core.pin;}catch(e){/* Pin doesn't exist yet */}
  832. // check DDOS
  833. if(!locked && pin){
  834. if(!!(+windw.specialData.config.ddos) && (+killcount.innerHTML - oldamount) > (+windw.specialData.config.ddos/3)){
  835. locked = true;
  836. // LOCK THE GAME!
  837. // 2.12.0 - Repeats every 0.25 seconds until the game is actually locked.
  838. const lockPacket = [{
  839. channel: "/service/player",
  840. clientId,
  841. data: {
  842. gameid: pin,
  843. type: "lock"
  844. },
  845. ext: {},
  846. id: ++messageId
  847. }];
  848. e.webSocket.send(JSON.stringify(lockPacket));
  849. windw.specialData.lockInterval = setInterval(()=>{
  850. lockPacket.id = ++messageId;
  851. e.webSocket.send(JSON.stringify(lockPacket));
  852. },250);
  853. console.log("[ANTIBOT] - Detected bot spam. Locking game for 1 minute.");
  854. if(windw.specialData.config.counters){
  855. const ddoscount = document.createElement("div");
  856. let int = 60;
  857. ddoscount.innerHTML = `<span class="antibot-count-num">60</span>
  858. <span class="antibot-count-desc">Until Unlock</span>`;
  859. counters.append(ddoscount);
  860. const countTimer = setInterval(()=>{
  861. ddoscount.querySelector(".antibot-count-num").innerHTML = --int;
  862. if(int <= 0){
  863. clearInterval(countTimer);
  864. ddoscount.outerHTML = "";
  865. }
  866. },1e3);
  867. }
  868. setTimeout(()=>{
  869. locked = false;
  870. clearInterval(windw.specialData.lockInterval);
  871. // UNLOCK GAME
  872. console.log("[ANTIBOT] - Unlocking game.");
  873. e.webSocket.send(JSON.stringify([{
  874. channel: "/service/player",
  875. clientId,
  876. data: {
  877. gameid: pin,
  878. type: "unlock"
  879. },
  880. ext: {},
  881. id: ++messageId
  882. }]));
  883. },60e3);
  884. }
  885. }
  886. /*console.log(e); from testing: e[.webSocket] is the websocket*/
  887. const data = JSON.parse(t.data)[0];
  888. /*console.log(data);*/
  889. messageId = data.id ? data.id : messageId;
  890. /*if the message is the first message, which contains important clientid data*/
  891. if(data.id === "1"){
  892. clientId = data.clientId;
  893. }
  894. /*if the message is a player join message*/
  895. if(data.data && data.data.type === "joined"){
  896. console.warn("[ANTIBOT] - determining evil...");
  897. determineEvil(data.data,e.webSocket);
  898. specialBotDetector(data.data.type,data.data,e.webSocket);
  899. // Player was not banned.
  900. if(windw.specialData.inLobby && windw.specialData.config.start_lock !== 0 && windw.specialData.globalFuncs && windw.specialData.globalFuncs.gameOptions.automaticallyProgressGame){
  901. if(windw.specialData.lobbyLoadTime === 0){
  902. windw.specialData.lobbyLoadTime = Date.now();
  903. if(windw.specialData.config.counters){
  904. const c = document.createElement("div");
  905. c.innerHTML = `<span class="antibot-count-num">${Math.round((windw.specialData.config.start_lock - (Date.now() - windw.specialData.lobbyLoadTime)/1000))}</span>
  906. <span class="antibot-count-desc">Until Auto-Start</span>`;
  907. const i = setInterval(()=>{
  908. let t = Math.round((windw.specialData.config.start_lock - (Date.now() - windw.specialData.lobbyLoadTime)/1000));
  909. if(t < 0){
  910. t = "Please Wait...";
  911. }
  912. c.querySelector(".antibot-count-num").innerHTML = t;
  913. },1e3);
  914. counters.append(c);
  915. windw.specialData.StartLockElem = c;
  916. windw.specialData.StartLockInterval = i;
  917. }
  918. }
  919. if(Date.now() - windw.specialData.lobbyLoadTime > windw.specialData.config.start_lock * 1000){
  920. // max time passed, just start the darn thing!
  921. const {controllers} = windw.specialData.globalFuncs;
  922. if(controllers.filter((controller)=>{
  923. return !controller.isGhost && !controller.hasLeft;
  924. }).length === 0){
  925. // The only current player in the lobby.
  926. windw.specialData.lobbyLoadTime = Date.now();
  927. }else{
  928. windw.specialData.globalFuncs.startQuiz();
  929. if(windw.specialData.StartLockElem){
  930. clearInterval(windw.specialData.StartLockInterval);
  931. windw.specialData.StartLockElem.outerHTML = "";
  932. windw.specialData.StartLockElem = null;
  933. }
  934. }
  935. }
  936. }
  937. }else if(data.data && data.data.id === 45){
  938. // if player answers
  939. if(windw.specialData.kahootCore.game.navigation.currentGameBlockIndex === 0
  940. && windw.specialData.globalQuizData.questions[0].isAntibotQuestion){
  941. windw.specialData.CAPTCHA_IDS.add(data.data.cid);
  942. // if incorrect answer
  943. let choice = -1;
  944. try{
  945. choice = JSON.parse(data.data.content).choice;
  946. }catch(e){/* Likely invalid answer */}
  947. if(choice !== windw.specialData.globalQuizData.questions[0].AntibotCaptchaCorrectIndex){
  948. // BAN!
  949. const packet = createKickPacket(data.data.cid);
  950. e.webSocket.send(JSON.stringify(packet));
  951. delete windw.cachedData[data.data.cid];
  952. delete windw.specialData.kahootCore.game.core.controllers[data.data.cid];
  953. killcount.innerHTML = +killcount.innerHTML + 1;
  954. console.error("[ANTIBOT] - Bot banned. Failed the captcha.");
  955. }
  956. }
  957. if(Date.now() - windw.specialData.startTime < 500 && windw.specialData.config.timeout){
  958. throw "[ANTIBOT] - Answer was too quick!";
  959. }
  960. // if player just recently joined (within 1 second)
  961. if(windw.cachedData[data.data.cid] && Date.now() - windw.cachedData[data.data.cid].loginTime < 1000){
  962. const packet = createKickPacket(data.data.cid);
  963. windw.e.webSocket.send(JSON.stringify(packet));
  964. killcount.innerHTML = +killcount.innerHTML + 1;
  965. delete windw.cachedData[data.data.cid];
  966. throw `[ANTIBOT] - Bot with id ${data.data.cid} banned. Answered too quickly after joining.`;
  967. }
  968. }else if(data.data && data.data.id === 50){
  969. windw.cachedData[data.data.cid].tries++;
  970. if(windw.cachedData[data.data.cid].tries > 3){
  971. const kicker = createKickPacket(data.data.cid);
  972. e.webSocket.send(JSON.stringify(kicker));
  973. const name = windw.cachedUsernames.filter(o=>{return o.id == data.data.cid;}).length ? windw.cachedUsernames.filter(o=>{return o.id == data.data.cid;})[0].name : "bot";
  974. console.warn(`[ANTIBOT] - Bot ${name} banished. Seen spamming 2FA`);
  975. windw.cachedUsernames.forEach(o=>{
  976. if(o.id == windw.specialData.lastFakeUserID){
  977. o.banned = true;
  978. o.time = 10;
  979. return;
  980. }
  981. });
  982. delete windw.cachedData[data.data.cid];
  983. killcount.innerHTML = +killcount.innerHTML + 1;
  984. }
  985. }else if(data.data && data.data.id === 18) {
  986. teamBotDetector(JSON.parse(data.data.content),data.data.cid,e.webSocket);
  987. }else if(data.data && data.data.status === "LOCKED"){
  988. clearInterval(windw.specialData.lockInterval);
  989. }
  990. };
  991. // remove loaded modules (allows turning off things to be a bit easier)
  992. delete localStorage.kahootThemeScript;
  993. delete localStorage.extraCheck;
  994. delete localStorage.extraCheck2;
  995. },
  996. mainScript = new XMLHttpRequest();
  997. mainScript.open("GET","https://play.kahoot.it/"+script2);
  998. mainScript.send();
  999. mainScript.onload = ()=>{
  1000. let sc = mainScript.response;
  1001. // Access the namerator option
  1002. const nr = /=[a-z]\.namerator/gm,
  1003. letter = sc.match(nr)[0].match(/[a-z](?=\.)/g)[0];
  1004. sc = sc.replace(sc.match(nr)[0],`=(()=>{console.log(${letter}.namerator);windw.isUsingNamerator = ${letter}.namerator;return ${letter}.namerator})()`);
  1005. // Access the currentQuestionTimer and change the question time
  1006. const cqtr = /currentQuestionTimer:[a-z]\.payload\.questionTime/gm,
  1007. letter2 = sc.match(cqtr)[0].match(/[a-z](?=\.payload)/g)[0];
  1008. sc = sc.replace(sc.match(cqtr)[0],`currentQuestionTimer:${letter2}.payload.questionTime + (()=>{return (windw.specialData.config.additionalQuestionTime * 1000) || 0})()`);
  1009. // Access the "NoStreakPoints", allowing it to be enabled
  1010. const nsr = /[a-zA-Z]{2}\.NoStreakPoints/gm;
  1011. sc = sc.replace(sc.match(nsr)[0],"windw.specialData.config.streakBonus || 2"); // yes = 1, no = 2
  1012. // Access the StartQuiz function. Also gains direct access to the controllers!
  1013. const sq = /=[a-zA-Z]\.startQuiz/gm,
  1014. letter4 = sc.match(sq)[0].match(/[a-zA-Z](?=\.)/g)[0];
  1015. sc = sc.replace(sc.match(sq)[0],`=(()=>{
  1016. windw.specialData.globalFuncs = ${letter4};
  1017. return ${letter4}.startQuiz})()`);
  1018. // Access the fetched quiz information. Allows the quiz to be modified when the quiz is fetched!
  1019. const fqr = /RETRIEVE_KAHOOT_ERROR",[\w\d]{2}=function\([a-z]\){return Object\([\w$\d]{2}\.[a-z]\)\([\w\d]{2},{response:[a-z]}\)}/gm,
  1020. letter5 = sc.match(fqr)[0].match(/response:[a-z]/g)[0].split(":")[1],
  1021. fqrt = sc.match(fqr)[0];
  1022. sc = sc.replace(fqrt,`RETRIEVE_KAHOOT_ERROR",${fqrt.split("RETRIEVE_KAHOOT_ERROR\",")[1].split("response:")[0]}response:(()=>{
  1023. windw.specialData.globalQuizData = ${letter5};
  1024. windw.specialData.extraQuestionSetup(${letter5});
  1025. return ${letter5};
  1026. })()})}`);
  1027. // Access the core data
  1028. const cr = /[a-z]\.game\.core/m,
  1029. letter6 = sc.match(cr)[0].match(/[a-z](?=\.game)/)[0];
  1030. sc = sc.replace(cr,`(()=>{
  1031. if(typeof windw !== "undefined"){
  1032. windw.specialData.kahootCore = ${letter6};
  1033. }
  1034. return ${letter6}.game.core;
  1035. })()`);
  1036. let changed = originalPage.split("</body>");
  1037. changed = `${changed[0]}<script>${patchedScript}</script><script>${sc}</script><script>try{(${window.localStorage.kahootThemeScript})();}catch(err){}try{(${window.localStorage.extraCheck})();}catch(err){}window.setupAntibot = ${code.toString()};window.parent.fireLoaded = window.fireLoaded = true;window.setupAntibot();</script></body>${changed[1]}`;
  1038. console.log("[ANTIBOT] - loaded");
  1039. document.open();
  1040. document.write("<style>body{margin:0;}iframe{border:0;width:100%;height:100%;}</style><iframe src=\"about:blank\"></iframe>");
  1041. document.close();
  1042. window.stop();
  1043. const doc = document.querySelector("iframe");
  1044. doc.contentDocument.write(changed);
  1045. document.title = doc.contentDocument.title;
  1046. };
  1047. };
  1048. };