From 607338b3f1ae568a7c7d155efbee9e388acb9951 Mon Sep 17 00:00:00 2001 From: EthanHarv Date: Thu, 29 Jul 2021 23:30:41 -0500 Subject: [PATCH] Automatic new-account creation. --- slader-limit-bypass/js/quizlet_bypass.js | 196 +++++++---------------- 1 file changed, 59 insertions(+), 137 deletions(-) diff --git a/slader-limit-bypass/js/quizlet_bypass.js b/slader-limit-bypass/js/quizlet_bypass.js index 9e11844..5363758 100644 --- a/slader-limit-bypass/js/quizlet_bypass.js +++ b/slader-limit-bypass/js/quizlet_bypass.js @@ -1,152 +1,74 @@ -// TODO: Sidestep race condition in a less patchwork manner -setTimeout(function(){ renderBypass(); /* TODO: Check if it actually went through */ }, 1250); +// Remove 'x' free solutions badge. +if (document.querySelector('.b1if8dab')) { document.querySelector('.b1if8dab').style.display = "none"; } +checkIfNewAccountNeeded(); -function renderBypass() +function checkIfNewAccountNeeded() { - // Setup page elements - - //Get Katex CSS - var katex_css = document.createElement('link'); - katex_css.setAttribute('rel','stylesheet'); - katex_css.setAttribute('href','https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.css '); - document.head.appendChild(katex_css); + // Three cases: Almost out of solutions, not logged in at all, or out of solutions. - // Get the webpage data, devoid of any headers or cookies. Acts as if the user is not logged in at all. - doFetch(window.location).then(data => { processData(data); }) - -} -function processData(data){ - // Clear the "hidden explanation" out and replace it with a blank explanation area. - // The innermost item is ".s1i7awl8" - document.querySelector('main .mwhvwas').innerHTML = '

Explanation

'; - var expArea = document.querySelector('.sladerBypass .s1i7awl8') - - // Render new stuff - - // Is this an abomination? Yes. - // Does it work? Also yes. - // - // ... - // - // I don't want to talk about it. - // - var json = data.match(/(?<=window.Quizlet\["(questionDetailsPageData|textbookExercisePageData)"] = ).+?(?=; QLoad\("Quizlet.(questionDetailsPageData|textbookExercisePageData)")/gm); - if (!json) + // Almost out of solutions + if (document.querySelector('.b1m16m5o') && document.querySelector('.b1m16m5o').textContent == "This is your last free explanation") { - // Display ratelimit message - expArea.innerHTML = `

You have been ratelimited by Quizlet


Try clearing your cookies for Quizlet and reloading this page, this usually fixes it.
— Slader Bypass.
`; + signUpNewAccount(false); } + // Not logged in + else if (document.querySelector('.t1qexa4p') && document.querySelector('.t1qexa4p').textContent == "Create a free account to see explanations") + { + signUpNewAccount(true); + } + // Out of solutions + else if (document.querySelector('.sukvi6d') && document.querySelector('.sukvi6d').textContent == "YOU'VE REACHED YOUR FREE LIMIT") + { + signUpNewAccount(true); + } +} - // Parse JSON data - var qDetails = JSON.parse(json[0]); - var solutions = (qDetails.question || qDetails.exercise).solutions; - // Display JSON data as answer - solutionNum = 0; - solutions.forEach(solution => { - solutionNum++; - expArea.appendChild(document.createElement('hr')); - var h1 = document.createElement('h1'); - h1.textContent = 'Solution ' + solutionNum + ":"; - expArea.appendChild(h1); - const numSteps = solution.steps.length; - solution.steps.forEach(step => { - const stepNum = step.stepNumber; - // Create card element - var div = document.createElement('div'); - // Insert boilerplate card data - div.innerHTML = '

'; - // Step X: .s39tzu2 - div.querySelector('.s39tzu2').textContent = (numSteps === stepNum) ? "Result" : "Step " + stepNum; - // x of x: .sb9ch1t - div.querySelector('.sb9ch1t').textContent = stepNum + ' of ' + numSteps; - - // I'm not 100% on the structure of these, but I'll take a stab at it. - // It seems that only one column is ever used. I'll iterate anyways, because I can't trust that. - step.columns.forEach(column => { - var columnDiv = document.createElement('div'); - // Insert inner text - if (column.text) - { - var textDiv = document.createElement('div'); - textDiv.classList.add('sladerBypassKatexTextArea') - textDiv.textContent = column.text.replaceAll('\n\n\n', '\n\n'); // The replace call is a bit funky but it works. - columnDiv.appendChild(textDiv); - } - // Insert image, if applicable - if (column.images.additional) - { - var image = document.createElement('img'); - image.setAttribute('src', column.images.additional.regular.srcUrl); - columnDiv.appendChild(image); - } +function signUpNewAccount(doesReload) +{ + // We're just gonna assume this is a large enough characterspace for it to never matter. + var email = "sq_bypass_" + randomString(10, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'); - // Append server-rendered image src url. Used in errorhandling. (See: handleKatexError()) - if (column.images.latex && column.images.latex.large) - { - div.querySelector('.sladerBypassKatex').setAttribute('katexsrc', column.images.latex.large.srcUrl); - } + // Same thing ^ + var username = "sq_bypass_" + randomString(10, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'); - div.querySelector('.sladerBypassKatex').appendChild(columnDiv); - }); - - // Append card to explanation area. - expArea.appendChild(div); - }); - }); - - // Render Katex for each card - expArea.querySelectorAll('.sladerBypassKatex').forEach(textArea => { - try { - renderMathInElement(textArea, { - delimiters: [ - {left: "$$", right: "$$", display: true}, - {left: "$", right: "$", display: false}, - {left: "\\(", right: "\\)", display: false}, - {left: "\\begin{equation}", right: "\\end{equation}", display: true}, - {left: "\\begin{align}", right: "\\end{align}", display: true}, - {left: "\\begin{alignat}", right: "\\end{alignat}", display: true}, - {left: "\\begin{gather}", right: "\\end{gather}", display: true}, - {left: "\\begin{CD}", right: "\\end{CD}", display: true}, - {left: "\\[", right: "\\]", display: true} - ], - throwOnError : true, - errorCallback : function(a, b){ handleKatexError(a, b, textArea); } - }); - } catch (error) { - console.error('Katex experienced an error. Attempting to load image replacement.'); + var request = fetch("https://quizlet.com/webapi/3.2/direct-signup", { + "headers": { + "accept": "application/json", + "accept-language": "en-US,en;q=0.9", + "content-type": "application/json", + "cs-token": getToken(), + "sec-ch-ua": "\" Not;A Brand\";v=\"99\", \"Google Chrome\";v=\"91\", \"Chromium\";v=\"91\"", + "sec-ch-ua-mobile": "?0", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "x-requested-with": "XMLHttpRequest" + }, + "referrer": "https://quizlet.com/goodbye", + "referrerPolicy": "origin-when-cross-origin", + "body": "{\"TOS\":false,\"birth_day\":\"5\",\"birth_month\":\"5\",\"birth_year\":\"2000\",\"email\":\"" + email + "@example.com\",\"is_free_teacher\":\"2\",\"is_parent\":false,\"password1\":\"SladerBypassPassword\",\"redir\":\"https://quizlet.com/goodbye\",\"signupOrigin\":\"global-header-link\",\"screenName\":\"Logout/logoutMobileSplash\",\"username\":\"" + username + "\",\"marketing_opt_out\":false}", + "method": "POST", + "mode": "cors", + "credentials": "include" + }).then(function() + { + if (doesReload) + { + location.reload(); } }); + return true; }; -function handleKatexError(a, b, textArea) -{ - // Display Katex error - console.error(a); - console.error(b); +function randomString(length, chars) { + var result = ''; + for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)]; + return result; +}; - // Remove broken Katex - textArea.querySelector('.sladerBypassKatexTextArea').innerHTML = ''; - - // Fallback to server-rendered katex (I'm assuming they have better error detection there.) - var image = document.createElement('img'); - image.setAttribute('src', textArea.getAttribute('katexsrc')); - textArea.appendChild(image); -} - -async function doFetch(url) -{ - const response = await fetch(url, { - method: 'GET', // *GET, POST, PUT, DELETE, etc. - mode: 'cors', // no-cors, *cors, same-origin - cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached - credentials: 'omit', // include, *same-origin, omit - headers: { - }, - redirect: 'follow', // manual, *follow, error - referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url - body: null // body data type must match "Content-Type" header - }); - return response.text(); -} \ No newline at end of file +function getToken(){ + token = document.cookie.match("(?:^|;)\\s*" + "qtkn".replace(/[\-\[\]{}()*+?.,\\^$|#\s]/g, "$&") + "=([^;]*)"); + return decodeURIComponent(token[1]); +}; \ No newline at end of file