// ==UserScript== // @name Stormgain with 2Captcha // @description Solves Stormgain Miner Captcha (GeeTest) using 2Captcha service // @version 0.2 // @author satology // @namespace sg2c.satology.onrender.com // @connect 2captcha.com // @connect miner.stormgain.com // @grant GM_xmlhttpRequest // @match https://app.stormgain.com/crypto-miner/ // @icon https://www.google.com/s2/favicons?sz=64&domain=stormgain.com // @downloadURL none // ==/UserScript== (function() { 'use strict'; /* Settings */ const API_KEY = 'YOUR_2CAPTCHA_API_KEY'; const DISPLAY_UI = true; // Let's you stop the auto process (to solve it manually) and shows some log msgs afterwards const COUNTDOWN_SECONDS = 9; // Time to wait before auto solving const LOG_TO_CONSOLE = true; // Shows log in console let preventStartCountdown = COUNTDOWN_SECONDS; let btn_start; let statusContainer; let statusElm; let itv_start; let itv_countdown; let snd_gt = ''; let snd_challenge = ''; let api_req_id = ''; let rsp_challenge = ''; let rsp_validate = ''; let rsp_seccode = ''; let sg_token = ''; let sg_clientId = ''; let api_in = function() { return `https://2captcha.com/in.php?key=${API_KEY}&json=1&method=geetest>=${snd_gt}&challenge=${snd_challenge}&pageurl=https://app.stormgain.com/crypto-miner/`; } let api_out = function() { return `https://2captcha.com/res.php?key=${API_KEY}&json=1&action=get&id=${api_req_id}`; }; let apiResponse = ''; function logger(title = '', msg = '') { if(!LOG_TO_CONSOLE) { return; } console.log("%c" + new Date().toISOString().slice(0, 19).replace("T", " ") + ' > ' + title, "background: yellow; font-size: large"); console.log(msg); } function toUI(msg) { if (DISPLAY_UI) { document.getElementById("sg2c-msg").innerHTML = msg; } } async function start() { try { sg_token = JSON.parse(localStorage.AppStorage).JWTAccessToken; logger('', 'JWTAccessToken retireved'); } catch(err) { logger('Unable to retrieve JWTAccessToken', err); toUI('Error!'); return; } try { sg_clientId = Object.keys(JSON.parse(localStorage.AppStorage).clientPrefs)[0]; toUI('CLientID retireved'); } catch(err) { logger('Unable to retrieve ClientID', err); toUI('Error!'); return; } let rr = await fetch("https://miner.stormgain.com/api/v1/preactivate", { "headers": { "accept": "application/json, text/plain, */*", "authorization": "Token " + sg_token, "client-id": sg_clientId }, "referrer": "https://app.stormgain.com/", "referrerPolicy": "strict-origin-when-cross-origin", "body": null, "method": "GET", "mode": "cors", "credentials": "omit" }); let content = await rr.json(); if (content && content.data && content.data.success && content.data.gt && content.data.challenge) { snd_gt = content.data.gt; snd_challenge = content.data.challenge; logger('', 'Challenge data retrieved'); } else { logger('Error retrieving challenge data', content); toUI('Error!'); return; } GM_xmlhttpRequest({ method: "GET", url: api_in(), onload: function(response) { apiResponse = JSON.parse(this.responseText); if (apiResponse.status == 0) { logger('Error in SG with captcha', apiResponse.error_text); toUI('Error!'); } else { api_req_id = apiResponse.request; logger('Captcha submitted', 'Request ID: ' + api_req_id); toUI('Captcha submitted'); setTimeout( () => { getSolved(); }, 15000 ); } }, onerror: function(e) { toUI('Error!'); logger('Error submitting captcha', e); } }); } function getSolved() { toUI('Waiting for solution...'); logger('', 'Retrieving solution'); GM_xmlhttpRequest({ method: "GET", url: api_out(), onload: function(response) { apiResponse = JSON.parse(this.responseText); logger('2C Response when retrieving', apiResponse); if (apiResponse.status == 0) { logger('2C Message', apiResponse.request); if (apiResponse.request == 'CAPCHA_NOT_READY') { toUI('Captcha not ready yet...'); setTimeout( () => { getSolved(); }, 15000 ); } else if (apiResponse.request == 'ERROR_CAPTCHA_UNSOLVABLE') { toUI('Refreshing for retry...'); setTimeout( () => { window.location.reload(); }, 2000); return; } else { if (apiResponse.error_text) { toUI('Error: ' + apiResponse.error_text); } if (apiResponse.request) { toUI('Error: ' + apiResponse.request); } } } else { rsp_challenge = apiResponse.request.geetest_challenge; rsp_validate = apiResponse.request.geetest_validate; rsp_seccode = apiResponse.request.geetest_seccode; toUI('Results ready. Processing...'); //TODO: send to SG if (rsp_challenge && rsp_validate && rsp_seccode) { logger('2C solved the captcha', 'Sending to SG'); sendToSg(); } } }, onerror: function(e) { logger('Unexpected error getting solution', e); toUI('Error!'); //TODO: retry in X seconds } }); } async function sendToSg() { logger('Sending to SG'); GM_xmlhttpRequest({ method: "POST", url: "https://miner.stormgain.com/api/v1/activate", headers: { "accept": "application/json, text/plain, */*", "authorization": "Token " + sg_token, "client-id": sg_clientId, "content-type": "multipart/form-data; boundary=----WebKitFormBoundaryGpbvA0qBtFeR1Kuw", "cookie": document.cookie, "referrer": "https://app.stormgain.com/", "referrerPolicy": "strict-origin-when-cross-origin", "mode": "cors", "credentials": "omit", }, // "data": "", "data": "------WebKitFormBoundaryGpbvA0qBtFeR1Kuw\r\nContent-Disposition: form-data; name=\"geetest_challenge\"\r\n\r\n" + rsp_challenge + "\r\n------WebKitFormBoundaryGpbvA0qBtFeR1Kuw\r\nContent-Disposition: form-data; name=\"geetest_seccode\"\r\n\r\n" + rsp_seccode + "\r\n------WebKitFormBoundaryGpbvA0qBtFeR1Kuw\r\nContent-Disposition: form-data; name=\"geetest_validate\"\r\n\r\n" + rsp_validate + "\r\n------WebKitFormBoundaryGpbvA0qBtFeR1Kuw--\r\n", onload: function(response) { logger('SG Response', response); apiResponse = JSON.parse(this.responseText); if (apiResponse.active) { toUI('Success. Refreshing...'); logger('SG accepted the solution', 'Refreshing...'); setTimeout( () => { window.location.reload(); }, 2000); } else { toUI('Error'); logger('Something went wrong. Check the SG Response', apiResponse); } }, onerror: function(e) { logger('Error sending solution to SG', e); toUI('Error!'); } }); return; } itv_start = setInterval( () => { btn_start = document.querySelector('.wrapper .activate'); if (btn_start) { clearInterval(itv_start); if (!DISPLAY_UI) { start(); return; } //load countdown/ui statusContainer = btn_start.parentNode.parentNode; statusContainer.innerHTML = `Solving in ${preventStartCountdown}... ` + statusContainer.innerHTML statusElm = document.getElementById('sg2c-countdown'); document.getElementById("sg2c-btn").addEventListener("click", function() { clearInterval(itv_countdown); let elements = document.getElementsByClassName('sg2c'); for (var element of elements) { element.remove(); } this.innerText = 'Navigate using the menu and come back to the Miner if the button doesn\'t work'; //this.remove(); return; }); itv_countdown = setInterval(() => { preventStartCountdown = preventStartCountdown-1; if (preventStartCountdown < 1) { clearInterval(itv_countdown); document.getElementById("sg2c-btn").remove(); document.getElementById("sg2c-msg").innerHTML = 'Started...'; start(); return; } if (statusElm) { statusElm.innerText = preventStartCountdown; } }, 1000); } }, 1000); })();