- // ==UserScript==
- // @name Kahoot AntiBot
- // @namespace http://tampermonkey.net/
- // @version 2.14.1
- // @icon https://cdn.discordapp.com/icons/641133408205930506/31c023710d468520708d6defb32a89bc.png
- // @description Remove all bots from a kahoot game.
- // @author theusaf
- // @copyright 2018-2021, Daniel Lau (https://github.com/theusaf/kahoot-antibot)
- // @match *://play.kahoot.it/*
- // @exclude *://play.kahoot.it/v2/assets/*
- // @grant none
- // @run-at document-start
- // @license MIT; https://opensource.org/licenses/MIT
- // ==/UserScript==
-
- // Notes: changing the questions AND questionIndex stuff works?
-
- if(window.fireLoaded || (window.parent && window.parent.page)){
- throw "[ANTIBOT] - page is loaded";
- }
- if(window.localStorage.extraCheck){
- console.log("[ANTIBOT] - Detected PIN Checker");
- }
- if(window.localStorage.kahootThemeScript){
- console.log("[ANTIBOT] - Detected KonoSuba Theme");
- }
- document.write("[ANTIBOT] - Patching Kahoot. Please wait. If this screen stays blank for long periods of time, please force reload or clear your cache.");
- window.url = window.location.href;
- window.page = new XMLHttpRequest();
- window.page.open("GET",window.url);
- window.page.send();
- window.page.onload = ()=>{
- const scriptURL = window.page.response.match(/><\/script><script .*?vendors.*?><\/script>/mg)[0].substr(9).split("src=\"")[1].split("\"")[0],
- script2 = window.page.response.match(/\/v2\/assets\/js\/main.*?(?=")/mg)[0];
- let originalPage = window.page.response.replace(/><\/script><script .*?vendors.*?><\/script>/mg,"></script>");
- originalPage = originalPage.replace(/\/v2\/assets\/js\/main.*?(?=")/mg,"data:text/javascript,");
- const script = new XMLHttpRequest();
- script.open("GET","https://play.kahoot.it/"+scriptURL);
- script.send();
- script.onload = ()=>{
- const patchedScriptRegex = /\.onMessage=function\([a-z],[a-z]\)\{/mg,
- letter1 = script.response.match(patchedScriptRegex)[0].match(/[a-z](?=,)/g)[0],
- letter2 = script.response.match(patchedScriptRegex)[0].match(/[a-z](?=\))/g)[0],
- patchedScript = script.response.replace(script.response.match(patchedScriptRegex)[0],`.onMessage=function(${letter1},${letter2}){window.globalMessageListener(${letter1},${letter2});`),
- code = ()=>{
- const windw = window.parent;
- window.windw = windw;
- // create watermark
- const container = document.createElement("div");
- container.id = "antibotwtr";
- const waterMark = document.createElement("p");
- waterMark.innerHTML = "v2.14.1 @theusaf";
- const botText = document.createElement("p");
- botText.innerHTML = "0";
- botText.id = "killcount";
- const menu = document.createElement("details");
- menu.innerHTML = `<summary>config</summary>
- <div id="antibot-settings">
- <!-- Timeout -->
- <div>
- <input type="checkbox" id="antibot.config.timeout"></input>
- <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>
- </div>
- <!-- Random Names -->
- <div>
- <input type="checkbox" id="antibot.config.looksRandom" checked="checked"></input>
- <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>
- </div>
- <!-- Blocking Format 1 -->
- <div>
- <input type="checkbox" id="antibot.config.blockformat1" checked="checked"></input>
- <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>
- </div>
- <!-- Blocking kahootflood.weebly.com -->
- <div>
- <input type="checkbox" id="antibot.config.blockservice1"></input>
- <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>
- </div>
- <!-- Block Numbers -->
- <div>
- <input type="checkbox" id="antibot.config.blocknum"></input>
- <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>
- </div>
- <!-- Block Non-Ascii -->
- <div>
- <input type="checkbox" id="antibot.config.forceascii"></input>
- <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>
- </div>
- <!-- Additional Question Time -->
- <div>
- <label class="antibot-input" for="antibot.config.teamtimeout" title="Add extra seconds to the question.">Additional Question Time</label>
- <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);">
- </div>
- <!-- Percent -->
- <div>
- <label class="antibot-input" for="antibot.config.percent" title="Specify the match percentage.">Match Percent</label>
- <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);">
- </div>
- <!-- DDOS -->
- <div>
- <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>
- <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);">
- </div>
- <!-- Auto-Start-Lock -->
- <div>
- <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>
- <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);">
- </div>
- <!-- Toggling Streak Bonus -->
- <div>
- <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')">
- <label for="antibot.config.streakBonus" title="Toggle the Streak Bonus.">Toggle Streak Bonus</label>
- </div>
- <!-- Show Antibot Counters -->
- <div>
- <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);">
- <label for="antibot.config.counters" title="Shows Antibot Countdowns (Lobby Auto-Start/Auto-Lock)">Show Antibot Timers</label>
- </div>
- <!-- Counter cheats -->
- <div>
- <input type="checkbox" id="antibot.config.counterCheats" onchange="windw.specialData.config.counterCheats = document.getElementById('antibot.config.counterCheats').checked;
- if(!windw.localStorage.antibotConfig){
- windw.localStorage.antibotConfig = JSON.stringify({});
- }
- const a = JSON.parse(windw.localStorage.antibotConfig);
- a.counterCheats = windw.specialData.config.counterCheats;
- localStorage.antibotConfig = JSON.stringify(a);
- if(a.counterCheats){
- // enable cheats
- alert('Changes may only take effect upon reload.');
- }else{
- // disable anti-cheat
- const q = windw.specialData.globalQuizData.questions;
- if(q[q.length - 1].isAntibotQuestion){
- q.splice(-1,1);
- delete windw.specialData.kahootCore.game.navigation.questionIndexMap[q.length];
- }
- }">
- <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>
- </div>
- <!-- CAPTCHA -->
- <div>
- <input type="checkbox" id="antibot.config.enableCAPTCHA" onchange="windw.specialData.config.enableCAPTCHA = document.getElementById('antibot.config.enableCAPTCHA').checked;
- if(!windw.localStorage.antibotConfig){
- windw.localStorage.antibotConfig = JSON.stringify({});
- }
- const a = JSON.parse(windw.localStorage.antibotConfig);
- a.enableCAPTCHA = windw.specialData.config.enableCAPTCHA;
- localStorage.antibotConfig = JSON.stringify(a);
- if(a.enableCAPTCHA){
- // enable captcha
- alert('Changes may only take effect upon reload.');
- }else{
- // disable captcha
- const q = windw.specialData.globalQuizData.questions;
- if(q[0].isAntibotQuestion){
- q.splice(0,1);
- delete windw.specialData.kahootCore.game.navigation.questionIndexMap[q.length];
- }
- }">
- <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>
- </div>
- </div>`;
- const counters = document.createElement("div");
- counters.id = "antibot-counters";
- const styles = document.createElement("style");
- styles.type = "text/css";
- styles.innerHTML = `#antibotwtr{
- position: fixed;
- bottom: 100px;
- right: 100px;
- font-size: 1rem;
- opacity: 0.4;
- transition: opacity 0.4s;
- z-index: 5000;
- background: white;
- text-align: center;
- border-radius: 0.5rem;
- }
- #antibotwtr summary{
- text-align: left;
- }
- #antibotwtr:hover{
- opacity: 1;
- }
- #antibotwtr p{
- display: inline-block;
- }
- #antibotwtr p:first-child{
- font-weight: 600;
- }
- #killcount{
- margin-left: 0.25rem;
- background: black;
- border-radius: 0.5rem;
- color: white;
- }
- #antibotwtr details{
- background: grey;
- }
- #antibotwtr input[type="checkbox"]{
- display: none;
- }
- #antibotwtr label{
- color: black;
- font-weight: 600;
- display: block;
- background: #c60929;
- border-radius: 0.5rem;
- height: 100%;
- word-break: break-word;
- }
- #antibotwtr .antibot-input{
- height: calc(100% - 1.5rem);
- background: #864cbf;
- color: white;
- }
- #antibotwtr input{
- position: absolute;
- bottom: 0;
- left: 0;
- width: 100%;
- height: 1rem;
- border-radius: 0.25rem;
- border: solid 1px black;
- }
- #antibotwtr input:checked+label{
- background: #26890c;
- }
- #antibot-settings{
- display: flex;
- flex-wrap: wrap;
- max-width: 25rem;
- max-height: 24rem;
- overflow: auto;
- }
- #antibot-settings > div{
- flex: 1;
- max-width: 33%;
- min-width: 33%;
- min-height: 6rem;
- box-sizing: border-box;
- position: relative;
- border: solid 0.5rem transparent;
- }
- #antibot-counters{
- position: absolute;
- right: 10rem;
- top: 11rem;
- font-size: 1.5rem;
- font-weight: 700;
- color: white;
- pointer-events: none;
- }
- #antibot-counters div{
- background: rgba(0,0,0,0.5);
- padding: 0.5rem;
- border-radius: 0.5rem;
- margin-bottom: 0.5rem;
- }
- .antibot-count-num{
- display: block;
- text-align: center;
- }
- .antibot-count-desc{
- text-align: center;
- font-size: 1.25rem;
- display: block;
- }`;
- container.append(waterMark,botText,menu);
- setTimeout(function(){
- if(document.body.innerText.split("\n").length < 8){ // assume broken. (just the water mark)
- const temp = document.createElement("template");
- temp.innerHTML = `<div id="antibot-broken-page" style="color: red; position: fixed; left: 0; top: 0; font-size: 1.25rem;line-height:1.75rem">
- <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>
- <hr/>
- <h2>Reload the page</h2>
- <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/>
- <h2>Clear the cache of this page and then reload.</h2><br/>
- <h2>Disable Kahoot AntiBot, reload the page, then re-enable Kahoot Antibot and reload the page again</h2>
- </div>`;
- document.body.append(temp.content.cloneNode(true));
- const RemoveBroke = setInterval(()=>{
- if(document.body.innerText.split("\n").length >= 20){
- clearInterval(RemoveBroke);
- document.getElementById("antibot-broken-page").outerHTML = "";
- }
- },1000);
- }
- },2000);
- document.body.append(container,styles,counters);
- const killcount = document.getElementById("killcount");
- windw.isUsingNamerator = false;
- windw.cachedUsernames = [];
- windw.confirmedPlayers = [];
- windw.cachedData = {};
- windw.loggedPlayers = {};
- windw.specialData = {
- extraQuestionSetup: (quiz)=>{
- if(windw.specialData.config.counterCheats){
- const len = quiz.questions.push({
- question:"[ANTIBOT] - This poll is for countering Kahoot cheating sites.",
- time:20000,
- type:"survey",
- isAntibotQuestion:true,
- choices:[{answer:"OK",correct:true}]
- });
- // windw.specialData.kahootCore.game.navigation.questionIndexMap[len - 1] = len - 1;
- }
- if(windw.specialData.config.enableCAPTCHA){
- const answers = ["red","blue","yellow","green"],
- images = [
- "https://cdn.discordapp.com/attachments/775828441127714837/798671584520568852/red.png",
- "https://cdn.discordapp.com/attachments/775828441127714837/798671580778594344/blue.png",
- "https://cdn.discordapp.com/attachments/775828441127714837/798671583178522685/yellow.png",
- "https://cdn.discordapp.com/attachments/775828441127714837/798671581962436619/green.png"
- ],
- imageIndex = Math.floor(Math.random() * answers.length);
- quiz.questions.splice(0,0,{
- question: `[ANTIBOT] - CAPTCHA: Please select ${answers[imageIndex]}`,
- time: 30000,
- type: "survey",
- isAntibotQuestion: true,
- AntibotCaptchaCorrectIndex: imageIndex,
- choices:[{answer:"OK"},{answer:"OK"},{answer:"OK"},{answer:"OK"}],
- image: images[imageIndex]
- });
- // windw.specialData.kahootCore.game.navigation.questionIndexMap[quiz.length - 1] = quiz.length - 1;
- }
- },
- startTime: 0,
- lastFakeLogin: 0,
- lastFakeUserID: 0,
- lastFakeUserName: "",
- config:{
- timeout: false,
- blocknum: false,
- looksRandom: true,
- banFormat1: true,
- additionalQuestionTime: null,
- percent: 0.6,
- streakBonus: 2,
- ddos: 0,
- start_lock: 0,
- counters: false,
- forceascii: false,
- blockservice1: false,
- enableCAPTCHA: false
- },
- inLobby: true,
- lobbyLoadTime: 0,
- lockInterval: null,
- kahootCore: null,
- globalFuncs: null,
- waitCounterCheats: null,
- waitEnableCaptcha: null,
- CAPTCHA_IDS: null
- };
- // loading localStorage info
- if(windw.localStorage.antibotConfig){
- const a = JSON.parse(windw.localStorage.antibotConfig);
- if(a.timeout){
- const t = document.getElementById("antibot.config.timeoutlbl");
- if(t){
- t.click();
- }
- }
- if(a.blocknum){
- const t = document.getElementById("antibot.config.blocknum");
- t.checked = true;
- windw.specialData.config.blocknum = true;
- }
- if(!a.looksRandom){
- const t = document.getElementById("antibot.config.lookrandlbl");
- if(t){
- t.click();
- }
- }
- if(a.teamtime){
- document.getElementById("antibot.config.teamtimeout").value = Number(a.teamtime);
- windw.specialData.config.additionalQuestionTime = Number(a.teamtime);
- }
- if(a.percent){
- document.getElementById("antibot.config.percent").value = Number(a.percent);
- windw.specialData.config.percent = Number(a.percent);
- }
- if(!a.banFormat1){
- document.getElementById("antibot.config.blockformat1").checked = false;
- windw.specialData.config.banFormat1 = false;
- }
- if(a.streakBonus == 1){
- document.getElementById("antibot.config.streakBonus").checked = true;
- windw.specialData.config.streakBonus = 1;
- }
- if(a.ddos){
- document.getElementById("antibot.config.ddos").value = +a.ddos;
- windw.specialData.config.ddos = +a.ddos;
- }
- if(a.start_lock){
- document.getElementById("antibot.config.start_lock").value = +a.start_lock;
- windw.specialData.config.start_lock = +a.start_lock;
- }
- if(a.counters){
- document.getElementById("antibot.config.counters").checked = true;
- windw.specialData.config.counters = true;
- }
- if(a.forceascii){
- document.getElementById("antibot.config.forceascii").checked = true;
- windw.specialData.config.forceascii = true;
- }
- if(a.blockservice1){
- document.getElementById("antibot.config.blockservice1").checked = true;
- windw.specialData.config.blockservice1 = true;
- }
- if(a.counterCheats){
- document.getElementById("antibot.config.counterCheats").checked = true;
- windw.specialData.config.counterCheats = true;
- }
- if(a.enableCAPTCHA){
- document.getElementById("antibot.config.enableCAPTCHA").checked = true;
- windw.specialData.config.enableCAPTCHA = true;
- }
- }
- let messageId = 0,
- clientId = null,
- pin = null;
- // for names like KaHOotSmaSH
- function looksRandom(name){
- // Assumes player names have either all caps, no caps, or up to 3 capital letters
- return !/(^(([^A-Z\n]*)?[A-Z]?([^A-Z\n]*)?){0,3}$)|^([A-Z]*)$/.test(name);
- }
- // for names like AmazingRobot32
- // also matches other somewhat suspicious names
- function isFakeValid(name){
- if(windw.specialData.config.blocknum && /\d/.test(name)){
- return true;
- }
- if(windw.specialData.config.forceascii && /[^\d\s\w_-]/.test(name)){
- return true;
- }
- 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);
- }
- function similarity(s1, s2) {
- // remove numbers from name if name is not only a number
- if(isNaN(s1) && typeof(s1) !== "object" && !windw.isUsingNamerator){
- s1 = s1.replace(/[0-9]/mg,"");
- }
- if(isNaN(s2) && typeof(s2) !== "object" && !windw.isUsingNamerator){
- s2 = s2.replace(/[0-9]/mg,"");
- }
- if(!s2){
- return 0;
- }
- // if is a number of the same length
- if(s1){
- if(!isNaN(s2) && !isNaN(s1) && s1.length == s2.length){
- return 1;
- }
- }
- // apply namerator rules
- if(windw.isUsingNamerator){
- if(!/^([A-Z][a-z]+){2,3}$/.test(s2)){
- return -1;
- }
- }
- if(!s1){
- return;
- }
- // ignore case
- s1 = s1.toLowerCase();
- s2 = s2.toLowerCase();
- let longer = s1,
- shorter = s2;
- // begin math to determine similarity
- if (s1.length < s2.length) {
- longer = s2;
- shorter = s1;
- }
- const longerLength = longer.length;
- if (longerLength == 0) {
- return 1.0;
- }
- return (longerLength - editDistance(longer, shorter)) / parseFloat(longerLength);
- }
- function editDistance(s1, s2) {
- s1 = s1.toLowerCase();
- s2 = s2.toLowerCase();
-
- const costs = new Array();
- for (let i = 0; i <= s1.length; i++) {
- let lastValue = i;
- for (let j = 0; j <= s2.length; j++) {
- if (i == 0){
- costs[j] = j;
- }
- else {
- if (j > 0) {
- let newValue = costs[j - 1];
- if (s1.charAt(i - 1) != s2.charAt(j - 1)){
- newValue = Math.min(Math.min(newValue,lastValue),costs[j]) + 1;
- }
- costs[j - 1] = lastValue;
- lastValue = newValue;
- }
- }
- }
- if (i > 0){
- costs[s2.length] = lastValue;
- }
- }
- return costs[s2.length];
- }
- function setup(){
- const launch_button =document.querySelectorAll("[data-functional-selector=\"launch-button\"]")[0];
- if(launch_button){
- console.warn("[ANTIBOT] - launch button found!");
- }else{
- setTimeout(setup,1000);
- }
- }
- setup();
- function clickName(name){
- const names = document.querySelectorAll("[data-functional-selector=player-name]");
- names.forEach(o=>{
- if(o.innerText == name){
- return o.click();
- }
- });
- }
- function createKickPacket(id){
- messageId++;
- return [{
- channel: "/service/player",
- clientId: clientId,
- id: String(Number(messageId)),
- data: {
- cid: String(id),
- content: JSON.stringify({
- kickCode: 1,
- quizType: "quiz"
- }),
- gameid: pin,
- host: "play.kahoot.it",
- id: 10,
- type: "message"
- },
- ext: {}
- }];
- }
- function determineEvil(player,socket){
- if(windw.cachedUsernames.length == 0){
- if(similarity(null,player.name) == -1){
- const packet = createKickPacket(player.cid);
- socket.send(JSON.stringify(packet));
- console.warn(`[ANTIBOT] - Bot ${player.name} has been banished`);
- killcount.innerHTML = +killcount.innerHTML + 1;
- delete windw.cachedData[player.cid];
- throw "[ANTIBOT] - Bot banned. Dont add";
- }
- windw.cachedUsernames.push({name: player.name, id:player.cid, time: 10, banned: false});
- windw.loggedPlayers[player.cid] = true;
- }else{
- let removed = false;
- if(similarity(null,player.name) == -1){
- removed = true;
- const packet1 = createKickPacket(player.cid);
- socket.send(JSON.stringify(packet1));
- console.warn(`[ANTIBOT] - Bot ${player.name} has been banished`);
- killcount.innerHTML = +killcount.innerHTML + 1;
- delete windw.cachedData[player.cid];
- throw "[ANTIBOT] - Bot banned. Dont add";
- }
- for(const i in windw.cachedUsernames){
- if(windw.confirmedPlayers.includes(windw.cachedUsernames[i].name)){
- continue;
- }
- if(similarity(windw.cachedUsernames[i].name,player.name) >= windw.specialData.config.percent){
- removed = true;
- const packet1 = createKickPacket(player.cid);
- socket.send(JSON.stringify(packet1));
- if(!windw.cachedUsernames[i].banned){
- const packet2 =createKickPacket(windw.cachedUsernames[i].id);
- windw.cachedUsernames[i].banned = true;
- socket.send(JSON.stringify(packet2));
- clickName(windw.cachedUsernames[i].name);
- killcount.innerHTML = +killcount.innerHTML + 1;
- }
- windw.cachedUsernames[i].time = 10;
- console.warn(`[ANTIBOT] - Bots ${player.name} and ${windw.cachedUsernames[i].name} have been banished`);
- killcount.innerHTML = +killcount.innerHTML + 1;
- delete windw.cachedData[player.cid];
- delete windw.cachedData[windw.cachedUsernames[i].id];
- throw "[ANTIBOT] - Bot banned. Dont add";
- }
- }
- if(!removed){
- windw.cachedUsernames.push({name: player.name,id: player.cid, time: 10, banned: false});
- windw.loggedPlayers[player.cid] = true;
- }
- }
- }
- function specialBotDetector(type,data,socket){
- switch (type) {
- case "joined":
- // if looks random
- if(windw.specialData.config.looksRandom){
- if(looksRandom(data.name)){
- const packet = createKickPacket(data.cid);
- socket.send(JSON.stringify(packet));
- killcount.innerHTML = +killcount.innerHTML + 1;
- windw.cachedUsernames.forEach(o=>{
- if(o.id == data.cid){
- o.banned = true;
- o.time = 10;
- return;
- }
- });
- throw `[ANTIBOT] - Bot ${data.name} banned; name too random.`;
- }
- }
- // if ban format 1 is enabled
- if(windw.specialData.config.banFormat1){
- if(/[a-z0-9]+[^a-z0-9\s][a-z0-9]+/gi.test(data.name)){
- const packet = createKickPacket(data.cid);
- socket.send(JSON.stringify(packet));
- killcount.innerHTML = +killcount.innerHTML + 1;
- windw.cachedUsernames.forEach(o=>{
- if(o.id == data.cid){
- o.banned = true;
- o.time = 10;
- return;
- }
- });
- throw `[ANTIBOT] - Bot ${data.name} banned; Name matches format [F][R][L].`;
- }
- }
- // special filters for kahootflood.weebly.com
- if(windw.specialData.config.blockservice1){
- if(data.name.replace(/[ᗩᗷᑕᗪEᖴGᕼIᒍKᒪᗰᑎOᑭᑫᖇᔕTᑌᐯᗯ᙭Yᘔ]/g,"").length / data.name.length < 0.5){
- const packet = createKickPacket(data.cid);
- socket.send(JSON.stringify(packet));
- killcount.innerHTML = +killcount.innerHTML + 1;
- windw.cachedUsernames.forEach(o=>{
- if(o.id == data.cid){
- o.banned = true;
- o.time = 10;
- return;
- }
- });
- throw `[ANTIBOT] - Bot ${data.name} banned; likely from kahootflood.weebly.com.`;
- }
- }
- 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
- windw.cachedData[data.cid] = {
- tries: 0,
- loginTime: Date.now()
- };
- }else{
- if(windw.cachedData[data.cid]){ // now allowing reconnection
- return;
- }
- const packet = createKickPacket(data.cid);
- socket.send(JSON.stringify(packet));
- console.warn(`[ANTIBOT] - Bot ${data.name} has been banished - invalid packet/name`);
- windw.cachedUsernames.forEach(o=>{
- if(o.id == data.cid){
- o.banned = true;
- o.time = 10;
- return;
- }
- });
- killcount.innerHTML = +killcount.innerHTML + 1;
- delete windw.cachedData[data.cid];
- throw "[ANTIBOT] - Bot banned. Dont add";
- }
- if(!windw.isUsingNamerator){
- if(isFakeValid(data.name)){
- if(Date.now() - windw.specialData.lastFakeLogin < 5000){
- if(windw.cachedData[windw.specialData.lastFakeUserID]){ // to get the first guy
- const packet = createKickPacket(windw.specialData.lastFakeUserID);
- socket.send(JSON.stringify(packet));
- clickName(windw.specialData.lastFakeUserName);
- delete windw.cachedData[windw.specialData.lastFakeUserID]; windw.cachedUsernames.forEach(o=>{
- if(o.id == windw.specialData.lastFakeUserID){
- o.banned = true;
- o.time = 10;
- return;
- }
- });
- }
- const packet = createKickPacket(data.cid);
- socket.send(JSON.stringify(packet));
- delete windw.cachedData[data.cid];
- windw.cachedUsernames.forEach(o=>{
- if(o.id == data.cid){
- o.banned = true;
- return;
- }
- });
- killcount.innerHTML = +killcount.innerHTML + 1;
- windw.specialData.lastFakeLogin = Date.now();
- windw.specialData.lastFakeUserID = data.cid;
- windw.specialData.lastFakeUserName = data.name;
- throw `[ANTIBOT] - Banned bot ${data.name}; their name is suspicious, likely a bot.`;
- }
- windw.specialData.lastFakeLogin = Date.now();
- windw.specialData.lastFakeUserID = data.cid;
- windw.specialData.lastFakeUserName = data.name;
- }
- }
- break;
- }
- }
- function teamBotDetector(team,cid,socket){
- let kick = false;
- if(team.length == 0 || team.indexOf("") != -1 || team.indexOf("Player 1") != -1 || team.join("") === "Youjustgotbotted" /* kahootflood.weebly.com */){
- kick = true;
- }
- if(kick){
- const packet = createKickPacket(cid);
- socket.send(JSON.stringify(packet));
- killcount.innerHTML = +killcount.innerHTML + 1;
- let name = "";
- delete windw.cachedData[cid];
- windw.cachedUsernames.forEach(o=>{
- name = o.name;
- if(o.id == cid){
- o.banned = true;
- o.time = 10;
- return;
- }
- });
- throw `[ANTIBOT] - Bot ${name} banned; invalid team members.`;
- }
- }
- // Cache Manager Timer
- setInterval(function(){
- for(const i in windw.cachedUsernames){
- if(windw.cachedUsernames[i].time <= 0 && !windw.cachedUsernames[i].banned && !windw.confirmedPlayers.includes(windw.cachedUsernames[i].name)){
- windw.confirmedPlayers.push(windw.cachedUsernames[i].name);
- continue;
- }
- if(windw.cachedUsernames[i].time <= -20){
- windw.cachedUsernames.splice(i,1);
- continue;
- }
- windw.cachedUsernames[i].time--;
- }
- },1000);
- // 2 Factor Auth Timer
- setInterval(()=>{
- for(const i in windw.cachedData){
- windw.cachedData[i].tries = 0;
- }
- },10000);
- windw.sendHandler = function(data,e){
- data = JSON.parse(data)[0];
- if(data.data){
- if(!data.data.id){
- return;
- }
- switch (data.data.id) {
- case 2:
- // question start
- windw.specialData.startTime = Date.now();
- windw.specialData.CAPTCHA_IDS = new Set;
- break;
- case 5:
- // restart
- windw.specialData.inLobby = true;
- windw.specialData.lobbyLoadTime = 0;
- break;
- case 10:
- if(data.data.content === "{}"){
- windw.specialData.inLobby = true;
- windw.specialData.lobbyLoadTime = 0;
- }
- break;
- case 9:
- // start
- windw.specialData.inLobby = false;
- if(windw.specialData.StartLockElem){
- clearInterval(windw.specialData.StartLockInterval);
- windw.specialData.StartLockElem.outerHTML = "";
- windw.specialData.StartLockElem = null;
- }
- break;
- case 4:
- // question end
- if(windw.specialData.kahootCore.game.navigation.currentGameBlockIndex === 0
- && windw.specialData.globalQuizData.questions[0].isAntibotQuestion){
- // boot all who did not answer
- const controllers = windw.specialData.kahootCore.game.core.controllers,
- answeredControllers = windw.specialData.CAPTCHA_IDS;
- for(const id in controllers){
- if(!answeredControllers.has(id)){
- const pack = createKickPacket(id);
- e.webSocket.send(JSON.stringify(pack));
- killcount.innerHTML = +killcount.innerHTML + 1;
- console.error("[ANTIBOT] - Bot banned. Did not answer the CAPTCHA.");
- delete windw.cachedData[data.data.cid];
- delete controllers[id];
- }
- }
- }
- break;
- }
- }
- };
- let ExtraCheck2 = function(){};
- try{
- if(windw.localStorage.extraCheck2){
- ExtraCheck2 = new Function("return " + windw.localStorage.extraCheck2)();
- }
- }catch(e){/* Likely doesn't exist */}
- let oldamount = 0,
- locked = false;
- setInterval(()=>{
- oldamount = +killcount.innerHTML;
- },20e3);
- window.globalMessageListener = function(e,t){
- try{ExtraCheck2(e,t);}catch(e){console.error("[ANTIBOT] - Execution of PIN-CHECKER Failed: " + e);}
- windw.e = e;
- if(!windw.e.webSocket.oldSend){
- windw.e.webSocket.oldSend = windw.e.webSocket.send;
- windw.e.webSocket.send = function(data){
- windw.sendHandler(data,e);
- windw.e.webSocket.oldSend(data);
- };
- }
- try{pin = windw.specialData.kahootCore.game.core.pin;}catch(e){/* Pin doesn't exist yet */}
- // check DDOS
- if(!locked && pin){
- if(!!(+windw.specialData.config.ddos) && (+killcount.innerHTML - oldamount) > (+windw.specialData.config.ddos/3)){
- locked = true;
- // LOCK THE GAME!
- // 2.12.0 - Repeats every 0.25 seconds until the game is actually locked.
- const lockPacket = [{
- channel: "/service/player",
- clientId,
- data: {
- gameid: pin,
- type: "lock"
- },
- ext: {},
- id: ++messageId
- }];
- e.webSocket.send(JSON.stringify(lockPacket));
- windw.specialData.lockInterval = setInterval(()=>{
- lockPacket.id = ++messageId;
- e.webSocket.send(JSON.stringify(lockPacket));
- },250);
- console.log("[ANTIBOT] - Detected bot spam. Locking game for 1 minute.");
- if(windw.specialData.config.counters){
- const ddoscount = document.createElement("div");
- let int = 60;
- ddoscount.innerHTML = `<span class="antibot-count-num">60</span>
- <span class="antibot-count-desc">Until Unlock</span>`;
- counters.append(ddoscount);
- const countTimer = setInterval(()=>{
- ddoscount.querySelector(".antibot-count-num").innerHTML = --int;
- if(int <= 0){
- clearInterval(countTimer);
- ddoscount.outerHTML = "";
- }
- },1e3);
- }
- setTimeout(()=>{
- locked = false;
- clearInterval(windw.specialData.lockInterval);
- // UNLOCK GAME
- console.log("[ANTIBOT] - Unlocking game.");
- e.webSocket.send(JSON.stringify([{
- channel: "/service/player",
- clientId,
- data: {
- gameid: pin,
- type: "unlock"
- },
- ext: {},
- id: ++messageId
- }]));
- },60e3);
- }
- }
- /*console.log(e); from testing: e[.webSocket] is the websocket*/
- const data = JSON.parse(t.data)[0];
- /*console.log(data);*/
- messageId = data.id ? data.id : messageId;
- /*if the message is the first message, which contains important clientid data*/
- if(data.id === "1"){
- clientId = data.clientId;
- }
- /*if the message is a player join message*/
- if(data.data && data.data.type === "joined"){
- console.warn("[ANTIBOT] - determining evil...");
- determineEvil(data.data,e.webSocket);
- specialBotDetector(data.data.type,data.data,e.webSocket);
- // Player was not banned.
- if(windw.specialData.inLobby && windw.specialData.config.start_lock !== 0 && windw.specialData.globalFuncs && windw.specialData.globalFuncs.gameOptions.automaticallyProgressGame){
- if(windw.specialData.lobbyLoadTime === 0){
- windw.specialData.lobbyLoadTime = Date.now();
- if(windw.specialData.config.counters){
- const c = document.createElement("div");
- c.innerHTML = `<span class="antibot-count-num">${Math.round((windw.specialData.config.start_lock - (Date.now() - windw.specialData.lobbyLoadTime)/1000))}</span>
- <span class="antibot-count-desc">Until Auto-Start</span>`;
- const i = setInterval(()=>{
- let t = Math.round((windw.specialData.config.start_lock - (Date.now() - windw.specialData.lobbyLoadTime)/1000));
- if(t < 0){
- t = "Please Wait...";
- }
- c.querySelector(".antibot-count-num").innerHTML = t;
- },1e3);
- counters.append(c);
- windw.specialData.StartLockElem = c;
- windw.specialData.StartLockInterval = i;
- }
- }
- if(Date.now() - windw.specialData.lobbyLoadTime > windw.specialData.config.start_lock * 1000){
- // max time passed, just start the darn thing!
- const {controllers} = windw.specialData.globalFuncs;
- if(controllers.filter((controller)=>{
- return !controller.isGhost && !controller.hasLeft;
- }).length === 0){
- // The only current player in the lobby.
- windw.specialData.lobbyLoadTime = Date.now();
- }else{
- windw.specialData.globalFuncs.startQuiz();
- if(windw.specialData.StartLockElem){
- clearInterval(windw.specialData.StartLockInterval);
- windw.specialData.StartLockElem.outerHTML = "";
- windw.specialData.StartLockElem = null;
- }
- }
- }
- }
- }else if(data.data && data.data.id === 45){
- // if player answers
- if(windw.specialData.kahootCore.game.navigation.currentGameBlockIndex === 0
- && windw.specialData.globalQuizData.questions[0].isAntibotQuestion){
- windw.specialData.CAPTCHA_IDS.add(data.data.cid);
- // if incorrect answer
- let choice = -1;
- try{
- choice = JSON.parse(data.data.content).choice;
- }catch(e){/* Likely invalid answer */}
- if(choice !== windw.specialData.globalQuizData.questions[0].AntibotCaptchaCorrectIndex){
- // BAN!
- const packet = createKickPacket(data.data.cid);
- e.webSocket.send(JSON.stringify(packet));
- delete windw.cachedData[data.data.cid];
- delete windw.specialData.kahootCore.game.core.controllers[data.data.cid];
- killcount.innerHTML = +killcount.innerHTML + 1;
- console.error("[ANTIBOT] - Bot banned. Failed the captcha.");
- }
- }
- if(Date.now() - windw.specialData.startTime < 500 && windw.specialData.config.timeout){
- throw "[ANTIBOT] - Answer was too quick!";
- }
- // if player just recently joined (within 1 second)
- if(windw.cachedData[data.data.cid] && Date.now() - windw.cachedData[data.data.cid].loginTime < 1000){
- const packet = createKickPacket(data.data.cid);
- windw.e.webSocket.send(JSON.stringify(packet));
- killcount.innerHTML = +killcount.innerHTML + 1;
- delete windw.cachedData[data.data.cid];
- throw `[ANTIBOT] - Bot with id ${data.data.cid} banned. Answered too quickly after joining.`;
- }
- }else if(data.data && data.data.id === 50){
- windw.cachedData[data.data.cid].tries++;
- if(windw.cachedData[data.data.cid].tries > 3){
- const kicker = createKickPacket(data.data.cid);
- e.webSocket.send(JSON.stringify(kicker));
- 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";
- console.warn(`[ANTIBOT] - Bot ${name} banished. Seen spamming 2FA`);
- windw.cachedUsernames.forEach(o=>{
- if(o.id == windw.specialData.lastFakeUserID){
- o.banned = true;
- o.time = 10;
- return;
- }
- });
- delete windw.cachedData[data.data.cid];
- killcount.innerHTML = +killcount.innerHTML + 1;
- }
- }else if(data.data && data.data.id === 18) {
- teamBotDetector(JSON.parse(data.data.content),data.data.cid,e.webSocket);
- }else if(data.data && data.data.status === "LOCKED"){
- clearInterval(windw.specialData.lockInterval);
- }
- };
- // remove loaded modules (allows turning off things to be a bit easier)
- delete localStorage.kahootThemeScript;
- delete localStorage.extraCheck;
- delete localStorage.extraCheck2;
- },
- mainScript = new XMLHttpRequest();
- mainScript.open("GET","https://play.kahoot.it/"+script2);
- mainScript.send();
- mainScript.onload = ()=>{
- let sc = mainScript.response;
- // Access the namerator option
- const nr = /=[a-z]\.namerator/gm,
- letter = sc.match(nr)[0].match(/[a-z](?=\.)/g)[0];
- sc = sc.replace(sc.match(nr)[0],`=(()=>{console.log(${letter}.namerator);windw.isUsingNamerator = ${letter}.namerator;return ${letter}.namerator})()`);
- // Access the currentQuestionTimer and change the question time
- const cqtr = /currentQuestionTimer:[a-z]\.payload\.questionTime/gm,
- letter2 = sc.match(cqtr)[0].match(/[a-z](?=\.payload)/g)[0];
- sc = sc.replace(sc.match(cqtr)[0],`currentQuestionTimer:${letter2}.payload.questionTime + (()=>{return (windw.specialData.config.additionalQuestionTime * 1000) || 0})()`);
- // Access the "NoStreakPoints", allowing it to be enabled
- const nsr = /[a-zA-Z]{2}\.NoStreakPoints/gm;
- sc = sc.replace(sc.match(nsr)[0],"windw.specialData.config.streakBonus || 2"); // yes = 1, no = 2
- // Access the StartQuiz function. Also gains direct access to the controllers!
- const sq = /=[a-zA-Z]\.startQuiz/gm,
- letter4 = sc.match(sq)[0].match(/[a-zA-Z](?=\.)/g)[0];
- sc = sc.replace(sc.match(sq)[0],`=(()=>{
- windw.specialData.globalFuncs = ${letter4};
- return ${letter4}.startQuiz})()`);
- // Access the fetched quiz information. Allows the quiz to be modified when the quiz is fetched!
- 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,
- letter5 = sc.match(fqr)[0].match(/response:[a-z]/g)[0].split(":")[1],
- fqrt = sc.match(fqr)[0];
- sc = sc.replace(fqrt,`RETRIEVE_KAHOOT_ERROR",${fqrt.split("RETRIEVE_KAHOOT_ERROR\",")[1].split("response:")[0]}response:(()=>{
- windw.specialData.globalQuizData = ${letter5};
- windw.specialData.extraQuestionSetup(${letter5});
- return ${letter5};
- })()})}`);
- // Access the core data
- const cr = /[a-z]\.game\.core/m,
- letter6 = sc.match(cr)[0].match(/[a-z](?=\.game)/)[0];
- sc = sc.replace(cr,`(()=>{
- if(typeof windw !== "undefined"){
- windw.specialData.kahootCore = ${letter6};
- }
- return ${letter6}.game.core;
- })()`);
- let changed = originalPage.split("</body>");
- 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]}`;
- console.log("[ANTIBOT] - loaded");
- document.open();
- document.write("<style>body{margin:0;}iframe{border:0;width:100%;height:100%;}</style><iframe src=\"about:blank\"></iframe>");
- document.close();
- window.stop();
- const doc = document.querySelector("iframe");
- doc.contentDocument.write(changed);
- document.title = doc.contentDocument.title;
- };
- };
- };