Skip to content

Instantly share code, notes, and snippets.

@jishanshaikh4
Created June 15, 2022 03:54
Show Gist options
  • Save jishanshaikh4/cc2ab24665a0d14642bca6215a8a267a to your computer and use it in GitHub Desktop.
Save jishanshaikh4/cc2ab24665a0d14642bca6215a8a267a to your computer and use it in GitHub Desktop.
Tampermonkey script to solve Hcaptcha
// ==UserScript==
// @name Hcaptcha Solver with Browser Trainer(Automatically solves Hcaptcha in browser)
// @namespace Hcaptcha Solver
// @version 10.0
// @description Hcaptcha Solver in Browser | Automatically solves Hcaptcha in browser
// @match https://*.hcaptcha.com/*hcaptcha-challenge*
// @match https://*.hcaptcha.com/*checkbox*
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @run-at document-start
// @connect www.imageidentify.com
// @connect https://cdnjs.cloudflare.com
// @connect https://cdn.jsdelivr.net
// @connect https://unpkg.com
// @connect https://*.hcaptcha.com/*
// @require https://unpkg.com/[email protected]/browser/lib/jimp.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/tesseract.js/2.0.0-alpha.2/tesseract.min.js
// @require https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js
// @require https://cdn.jsdelivr.net/npm/@tensorflow-models/[email protected]/dist/coco-ssd.min.js
// @require https://cdn.jsdelivr.net/npm/@tensorflow-models/[email protected]/dist/mobilenet.min.js
/*
██╗░░██╗░█████╗░░█████╗░██████╗░████████╗░█████╗░██╗░░██╗░█████╗░  ░██████╗░█████╗░██╗░░░░░██╗░░░██╗███████╗██████╗░
██║░░██║██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██╔══██╗██║░░██║██╔══██╗  ██╔════╝██╔══██╗██║░░░░░██║░░░██║██╔════╝██╔══██╗
███████║██║░░╚═╝███████║██████╔╝░░░██║░░░██║░░╚═╝███████║███████║  ╚█████╗░██║░░██║██║░░░░░╚██╗░██╔╝█████╗░░██████╔╝
██╔══██║██║░░██╗██╔══██║██╔═══╝░░░░██║░░░██║░░██╗██╔══██║██╔══██║  ░╚═══██╗██║░░██║██║░░░░░░╚████╔╝░██╔══╝░░██╔══██╗
██║░░██║╚█████╔╝██║░░██║██║░░░░░░░░██║░░░╚█████╔╝██║░░██║██║░░██║  ██████╔╝╚█████╔╝███████╗░░╚██╔╝░░███████╗██║░░██║
╚═╝░░╚═╝░╚════╝░╚═╝░░╚═╝╚═╝░░░░░░░░╚═╝░░░░╚════╝░╚═╝░░╚═╝╚═╝░░╚═╝  ╚═════╝░░╚════╝░╚══════╝░░░╚═╝░░░╚══════╝╚═╝░░╚═╝
*/
/** Note: This script is solely intended for the use of educational purposes only and not to abuse any website.
*/
// ==/UserScript==
(async function() {
//TODO: Enable debug mode to print console logs
//TODO: Refactor Code for different models
'use strict';
var selectedImageCount = 0;
var tensorFlowModel = undefined;
var tensorFlowMobileNetModel = undefined;
var worker = undefined;
var identifiedObjectsList = [];
var exampleImageList = [];
var identifyObjectsFromImagesCompleted = false;
var currentExampleUrls = [];
//Default Language for hcaptcha
const LANG_ENGLISH = "English"
const DEFAULT_LANGUAGE = LANG_ENGLISH;
const ENABLE_DEFAULT_LANGUAGE = true;
//Guess/Match New Images
const MATCH_IMAGES_USING_TRAINER = false;
const GUESS_NEW_IMAGE_TYPE = false;
//Node Selectors
const CHECK_BOX = "#checkbox";
const SUBMIT_BUTTON = ".button-submit";
const TASK_IMAGE_BORDER = ".task-image .border";
const IMAGE = ".task-image .image";
const TASK_IMAGE = ".task-image";
const PROMPT_TEXT = ".prompt-text";
const NO_SELECTION = ".no-selection";
const CHALLENGE_INPUT_FIELD = ".challenge-input .input-field";
const CHALLENGE_INPUT = ".challenge-input";
const CHALLENGE_IMAGE = ".challenge-example .image .image";
const IMAGE_FOR_OCR = ".challenge-image .zoom-image";
const LANGUAGE_SELECTOR = "#language-list .scroll-container .option span";
//Attributes
const ARIA_CHECKED = "aria-checked";
const ARIA_HIDDEN = "aria-hidden";
//Values that can be changed for other languages
const AIRPLANE = "airplane";
const BICYCLE = "bicycle";
const BOAT = "boat";
const BUS = "bus";
const CAR = "car";
const MOTORBUS = "motorbus";
const MOTORCYCLE = "motorcycle";
const SURFBOARD = "surfboard";
const TRAIN = "train";
const TRUCK = "truck";
const TRIMARAN = "trimaran";
const SEAPLANE = "seaplane";
const SPEEDBOAT = "speedboat";
//Living Room Objects
const BED = "bed";
const BOOK = "book";
const CHAIR = "chair";
const CLOCK = "clock";
const COUCH = "couch";
const DINING_TABLE = "dining table";
const POTTED_PLANT = "potted plant";
const TV = "tv";
//Animals
const ZEBRA = "zebra";
const CAT = "cat";
const DOG = "dog";
// Vertical River
const VALLEY = "valley";
const VERTICAL_RIVER = "vertical river";
const LIVING_ROOM_TYPES = [BED, BOOK, CHAIR, CLOCK, COUCH, DINING_TABLE, POTTED_PLANT, TV];
const TRANSPORT_TYPES = [AIRPLANE, BICYCLE, BOAT, BUS, CAR, MOTORBUS, MOTORCYCLE, SEAPLANE, SPEEDBOAT, SURFBOARD, TRAIN, TRIMARAN, TRUCK];
const ANIMAL_TYPES = [ZEBRA, CAT, DOG];
const SENTENCE_TEXT_A = "Please click each image containing a ";
const SENTENCE_TEXT_AN = "Please click each image containing an ";
const LANGUAGE_FOR_OCR = "eng";
// Option to override the default image matching
// Enabling this by default
const ENABLE_TENSORFLOW = true;
// Max Skips that can be done while solving the captcha
// This is likely not to happen, if it occurs retry for new images
const MAX_SKIPS = 10;
var skipCount = 0;
var USE_MOBILE_NET = false;
var USE_COLOUR_PATTERN = false;
var NEW_WORD_IDENTIFIED = false;
//Probablility for objects
var probabilityForObject = new Map();
probabilityForObject.set("speedboat", 0.14);
probabilityForObject.set("fireboat", 0.4);
probabilityForObject.set("boathouse", 0.4);
probabilityForObject.set("submarine", 0.5);
probabilityForObject.set("printer", 0.05);
probabilityForObject.set("stretcher", 0.05);
probabilityForObject.set("rotisserie", 0.02);
probabilityForObject.set("spatula", 0.05);
String.prototype.includesOneOf = function(arrayOfStrings) {
//If this is not an Array, compare it as a String
if (!Array.isArray(arrayOfStrings)) {
return this.toLowerCase().includes(arrayOfStrings.toLowerCase());
}
for (var i = 0; i < arrayOfStrings.length; i++) {
if ((arrayOfStrings[i].substr(0, 1) == "=" && this.toLowerCase() == arrayOfStrings[i].substr(1).toLowerCase()) ||
(this.toLowerCase().includes(arrayOfStrings[i].toLowerCase()))) {
return true;
}
}
return false;
}
String.prototype.equalsOneOf = function(arrayOfStrings) {
//If this is not an Array, compare it as a String
if (!Array.isArray(arrayOfStrings)) {
return this.toLowerCase() == arrayOfStrings.toLowerCase();
}
for (var i = 0; i < arrayOfStrings.length; i++) {
if ((arrayOfStrings[i].substr(0, 1) == "=" && this.toLowerCase() == arrayOfStrings[i].substr(1).toLowerCase()) ||
(this.toLowerCase() == arrayOfStrings[i].toLowerCase())) {
return true;
}
}
return false;
}
// This script uses imageidentify API (wolfram) . You may also use TensorFlow.js, Yolo latest version to recognize common objects.
//(When the cloud service is available for yolo, we can switch the API endpoint). Accuracy varies between Wolfram, Tensorflow and Yolo.
// Use this as a reference to solve recaptcha/other captchas using scripts in browser. This is intended for learning purposes.
// Using TensorFlow as fallback, but this requires good CPU in order to solve quickly.
// CPU utilization and memory utlization may go high when using TensorFlow.js
function matchImages(imageUrl, word, i) {
GM_xmlhttpRequest({
method: "POST",
url: "https://www.imageidentify.com/objects/user-26a7681f-4b48-4f71-8f9f-93030898d70d/prd/urlapi/",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
data: "image=" + encodeURIComponent(imageUrl),
timeout: 8000,
onload: function(response) {
clickImages(response, imageUrl, word, i)
},
onerror: function(e) {
//Using Fallback TensorFlow
if (e && e.status && e.status != 0) {
console.log(e);
console.log("Using Fallback");
}
matchImagesUsingTensorFlow(imageUrl, word, i);
},
ontimeout: function() {
//console.log("Timed out. Using Fallback");
matchImagesUsingTensorFlow(imageUrl, word, i);
},
});
}
function matchImagesUsingTensorFlow(imageUrl, word, i) {
try {
let img = new Image();
img.crossOrigin = "Anonymous";
img.src = imageUrl;
img.onload = () => {
initializeTensorFlowModel().then(model => model.detect(img))
.then(function(predictions) {
var predictionslen = predictions.length;
for (var j = 0; j < predictionslen; j++) {
if (qSelectorAll(IMAGE)[i] && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) &&
qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 0 &&
predictions[j].class.includesOneOf(word)) {
qSelectorAll(TASK_IMAGE)[i].click();
break;
}
}
img.removeAttribute("src");
selectedImageCount = selectedImageCount + 1;
});
}
} catch (err) {
console.log(err.message);
}
}
function matchImagesUsingTensorFlowMobileNet(imageUrl, word, i) {
try {
let img = new Image();
img.crossOrigin = "Anonymous";
img.src = imageUrl;
img.onload = () => {
initializeTensorFlowMobilenetModel().then(model => model.classify(img))
.then(function(predictions) {
var predictionslen = predictions.length;
for (var j = 0; j < predictionslen; j++) {
var probability = 0.077;
if (probabilityForObject.get(predictions[j].className)) {
probability = probabilityForObject.get(predictions[j].className);
}
if (qSelectorAll(IMAGE)[i] && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) &&
qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 0 &&
predictions[j].className.includesOneOf(word) && predictions[j].probability > probability) {
qSelectorAll(TASK_IMAGE)[i].click();
break;
}
}
img.removeAttribute("src");
selectedImageCount = selectedImageCount + 1;
});
}
} catch (err) {
console.log(err.message);
}
}
// TODO: Generalize this logic
// Identifying this based on the observation of the images seen
// The actual way would be to scan the entire image to find the lake.
// Mobilenet model in browser js identifies the lake but does not provide coordinates
// to identify if it is horizontal or vertical
function matchImageForVerticalRiver(imageUrl, word, i) {
Jimp.read(imageUrl).then(function (data) {
data.getBase64(Jimp.AUTO, async function (err, src) {
var img = document.createElement("img");
img.setAttribute("src", src);
await img.decode();
var imageHeight = img.height;
var imageWidth = img.width;
var cropHeight = imageHeight - 0.03*imageHeight;
let url = src.replace(/^data:image\/\w+;base64,/, "");
let buffer = new Buffer(url, 'base64');
Jimp.read(buffer).then(function (data) {
data.crop(0, cropHeight, imageWidth, imageHeight)
.getBase64(Jimp.AUTO, async function (err, src) {
var img = document.createElement("img");
img.src = src;
await img.decode();
var c = document.createElement("canvas")
c.width = img.width;
c.height = img.height;
var ctx = c.getContext("2d");
ctx.drawImage(img, 0, 0);
var imageData = ctx.getImageData(0, 0, c.width, c.height);
var data = imageData.data;
var count = 0;
//Multiple combinations and distances are required for accuracy
for (let i = 0; i < data.length; i+= 4) {
if( (data[i] < 140 && data[i+1] < 110 && data[i+2] > 80 && data[i+3] == 255) ||
(data[i] < 200 && data[i+1] < 200 && data[i+2] > 140 && data[i+3] == 255)){
count++;
}
}
if(count > 0.001*(data.length/4) && count < data.length/8) {
if (qSelectorAll(IMAGE)[i] && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) &&
qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 0) {
qSelectorAll(TASK_IMAGE)[i].click();
}
}
img.removeAttribute("src");
selectedImageCount = selectedImageCount + 1;
});
});
img.removeAttribute("src");
});
});
}
// This approach is naive approch to store the images and retrieve
// The accuracy is 100% as long as you store the selected images
// Browser memory is used to store the images and gets cleared if you delete the browser cache and cookies
// You may use this to store images in remote place and retrive for quick access
// This approach is only used during urgent scenarios before training the images
// Image differnce can also be done with the stored images to identify new image based on the existing if they are nearly equal
function matchImagesUsingTrainer(imageUrl, word, i) {
Jimp.read(imageUrl).then(function (data) {
data.getBase64(Jimp.AUTO, async function (err, src) {
var trainerInterval = setInterval(function(){
if (!qSelectorAll(IMAGE)[i] || !(qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) ){
clearInterval(trainerInterval);
return;
}
if (qSelectorAll(IMAGE)[i] && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) &&
qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 0 && GM_getValue(src) && GM_getValue(src) == word) {
console.log("Retrieved image from trainer");
selectedImageCount = selectedImageCount + 1;
qSelectorAll(TASK_IMAGE)[i].click();
clearInterval(trainerInterval);
return;
}
// Overriding Previously Stored values
if (qSelectorAll(IMAGE)[i] && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) &&
qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 1 && GM_getValue(src) && GM_getValue(src) != word) {
console.log("Overriding image in the trainer");
selectedImageCount = selectedImageCount + 1;
GM_setValue(src,word);
console.log("Image Stored into database");
clearInterval(trainerInterval);
return;
}
if (qSelectorAll(IMAGE)[i] && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) &&
qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 1 && !GM_getValue(src)) {
selectedImageCount = selectedImageCount + 1;
GM_setValue(src,word);
console.log("Image Stored into database");
clearInterval(trainerInterval);
return;
}
},5000);
});
});
}
//Function to sleep or delay
async function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
//Different Models can be set later based on usecase
//Ref Models: https://github.com/tensorflow/tfjs-models
async function initializeTensorFlowModel() {
if (!tensorFlowModel) {
tensorFlowModel = await cocoSsd.load();
}
return tensorFlowModel;
}
//MobileNet ssd model
async function initializeTensorFlowMobilenetModel() {
if (!tensorFlowMobileNetModel) {
tensorFlowMobileNetModel = await mobilenet.load();
}
return tensorFlowMobileNetModel;
}
//Initialize TesseractWorker
function initializeTesseractWorker() {
if (!worker) {
worker = new Tesseract.TesseractWorker();
}
}
function clickImages(response, imageUrl, word, i) {
try {
if (response && response.responseText && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) &&
qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 0) {
var responseJson = JSON.parse(response.responseText);
if (responseJson.identify && responseJson.identify.title && responseJson.identify.title.includesOneOf(word)) {
qSelectorAll(TASK_IMAGE)[i].click();
} else if (responseJson.identify && responseJson.identify.entity && responseJson.identify.entity.includesOneOf(word)) {
qSelectorAll(TASK_IMAGE)[i].click();
} else if (responseJson.identify && responseJson.identify.alternatives) {
var alternatives = JSON.stringify(responseJson.identify.alternatives);
var alternativesJson = JSON.parse(alternatives);
for (var key in alternativesJson) {
if (alternativesJson.hasOwnProperty(key)) {
if ((alternativesJson[key].includesOneOf(word) || key.includesOneOf(word))) {
qSelectorAll(TASK_IMAGE)[i].click();
break;
}
}
}
} else {
//No Match found
}
selectedImageCount = selectedImageCount + 1;
} else {
//console.log("Using Fallback TensorFlow");
matchImagesUsingTensorFlow(imageUrl, word, i);
}
} catch (err) {
//Using Fallback TensorFlow
//console.log(err.message);
//console.log("Using Fallback TensorFlow");
matchImagesUsingTensorFlow(imageUrl, word, i);
}
}
function qSelectorAll(selector) {
return document.querySelectorAll(selector);
}
function qSelector(selector) {
return document.querySelector(selector);
}
async function getSynonyms(word) {
USE_MOBILE_NET = false;
USE_COLOUR_PATTERN = false;
NEW_WORD_IDENTIFIED = false;
//TODO: Format this to JSON string
if (word == MOTORBUS || word == BUS) {
word = ['bus', 'motorbus'];
USE_MOBILE_NET = true;
} else if (word == CAR) {
word = ['=car', 'coupe', 'jeep', 'limo', 'sport utility vehicle', 'station wagon', 'hatchback', 'bumper car', 'modelT', 'electric battery', 'cruiser'];
USE_MOBILE_NET = true;
} else if (word == AIRPLANE) {
word = ['airplane', 'plane', 'aircraft', 'aeroplane', 'hangar', 'Airdock', 'JumboJet', 'jetliner', 'stealth fighter', 'field artillery']
USE_MOBILE_NET = true;
} else if (word == TRAIN) {
word = ['train', 'rail', 'cable car', 'locomotive', 'subway station']
USE_MOBILE_NET = true;
} else if (word == BOAT || word == SURFBOARD) {
word = ['=boat', '=barge', 'houseboat', 'boathouse', 'speedboat', '=submarine', 'bobsled', 'catamaran', 'schooner', 'ocean liner', 'lifeboat', 'fireboat', 'yawl', 'pontoon', 'small boat', 'SnowBlower', 'Sea-coast', 'paddlewheel', 'paddle wheel', 'PaddleSteamer', 'Freighter', 'Sternwheeler', 'kayak', 'canoe', 'deck', 'DockingFacility', 'surfboard', '=ship', '=cruise', 'watercraft', 'sail', 'canvas', '=raft']
USE_MOBILE_NET = true;
} else if (word == BICYCLE) {
word = ['bicycle-built-for-two', 'tandem bicycle', 'bicycle', 'tricycle', 'mountain bike', 'AcceleratorPedal', 'macaw', 'knot']
USE_MOBILE_NET = true;
} else if (word == MOTORCYCLE) {
word = ['moped', 'motor scooter', 'scooter', 'motorcycle', 'windshield', 'dashboard']
USE_MOBILE_NET = true;
} else if (word == TRUCK) {
word = ['truck', 'cargocontainer', 'bazooka']
USE_MOBILE_NET = true;
} else if (word == TRIMARAN || word == SPEEDBOAT || word == SEAPLANE) {
word = ['spatula', 'can opener', 'tin opener', 'monitor', 'screen', 'stretcher', 'printer', 'nail', 'mousetrap', 'TRIMARAN', 'space shuttle', 'ski', 'rotisserie', 'geyser', 'plate rack']
USE_MOBILE_NET = true;
} else if (word.includesOneOf(LIVING_ROOM_TYPES)) {
word = ['bed', 'couch', 'chair', 'potted plant', 'dining table', 'clock', 'tv', 'book']
} else if (word == ZEBRA) {
word = ['zebra']
} else if (word == CAT) {
word = ['cat']
USE_MOBILE_NET = true;
} else if (word == DOG) {
word = ['dog']
} else if (word == VALLEY || word == VERTICAL_RIVER){
word = ['alp','volcano']
USE_COLOUR_PATTERN = true;
} else {
NEW_WORD_IDENTIFIED = true;
console.log("Word does not match. New type identified::" + word);
}
return word
}
function isHidden(el) {
return (el.offsetParent === null)
}
if (window.location.href.includes("checkbox")) {
var checkboxInterval = setInterval(function() {
if (!qSelector(CHECK_BOX)) {
//Wait until the checkbox element is visible
} else if (qSelector(CHECK_BOX).getAttribute(ARIA_CHECKED) == "true") {
clearInterval(checkboxInterval);
} else if (!isHidden(qSelector(CHECK_BOX)) && qSelector(CHECK_BOX).getAttribute(ARIA_CHECKED) == "false") {
qSelector(CHECK_BOX).click();
} else {
return;
}
}, 5000);
} else {
try {
await initializeTesseractWorker();
await initializeTensorFlowModel();
await initializeTensorFlowMobilenetModel();
selectImages();
} catch (err) {
console.log(err);
console.log("Tesseract could not be initialized");
}
}
function selectImagesAfterDelay(delay) {
setTimeout(function() {
selectImages();
}, delay * 1000);
}
function triggerEvent(el, type) {
var e = document.createEvent('HTMLEvents');
e.initEvent(type, false, true);
el.dispatchEvent(e);
}
function triggerMouseEvent(el, type) {
var e = document.createEvent('MouseEvent');
e.initEvent(type, false, true);
el.dispatchEvent(e);
}
// Small hack to select the nodes
function unsure(targetNodeText) {
var targetNode = Array.from(qSelectorAll('div'))
.find(el => el.textContent === targetNodeText);
//Works for now
//TODO: Select clothing
//TODO: Draw boxes around images
if (targetNode) {
triggerMouseEvent(targetNode, 'mousedown');
triggerMouseEvent(targetNode, 'mouseup');
if (qSelector(SUBMIT_BUTTON)) {
qSelector(SUBMIT_BUTTON).click();
}
}
return selectImagesAfterDelay(1);
}
function getUrlFromString(urlString) {
var imageUrl = urlString.substring(
urlString.indexOf('"') + 1,
urlString.lastIndexOf('"')
);
if (!imageUrl || !imageUrl.includes("https")) {
return 0;
}
return imageUrl;
}
function getImageList() {
var imageList = [];
if (qSelectorAll(IMAGE).length > 0) {
for (var i = 0; i < 9; i++) {
var urlString = qSelectorAll(IMAGE)[i].style.background;
var imageUrl = getUrlFromString(urlString);
if (imageUrl == 0) {
//console.log("Image url is empty");
return imageList;
}
imageList[i] = imageUrl;
}
}
return imageList;
}
function waitUntilImageSelection() {
var imageIntervalCount = 0;
var imageInterval = setInterval(function() {
imageIntervalCount = imageIntervalCount + 1;
if (selectedImageCount == 9) {
clearInterval(imageInterval);
if (qSelector(SUBMIT_BUTTON)) {
qSelector(SUBMIT_BUTTON).click();
}
return selectImagesAfterDelay(5);
} else if (imageIntervalCount > 8) {
clearInterval(imageInterval);
return selectImages();
} else if(selectedImageCount > 2 && MATCH_IMAGES_USING_TRAINER && NEW_WORD_IDENTIFIED && imageIntervalCount > 4){
clearInterval(imageInterval);
if (qSelector(SUBMIT_BUTTON)) {
qSelector(SUBMIT_BUTTON).click();
}
return selectImagesAfterDelay(5);
} else if(MATCH_IMAGES_USING_TRAINER && NEW_WORD_IDENTIFIED && imageIntervalCount > 6){
clearInterval(imageInterval);
if (qSelector(SUBMIT_BUTTON)) {
qSelector(SUBMIT_BUTTON).click();
}
return selectImagesAfterDelay(5);
}else{
}
}, 3000);
}
function waitForImagesToAppear() {
var checkImagesSelectedCount = 0;
var waitForImagesInterval = setInterval(function() {
checkImagesSelectedCount = checkImagesSelectedCount + 1;
if (qSelectorAll(IMAGE) && qSelectorAll(IMAGE).length == 9) {
clearInterval(waitForImagesInterval);
return selectImages();
} else if (checkImagesSelectedCount > 60) {
clearInterval(waitForImagesInterval);
} else if (qSelector(CHALLENGE_INPUT_FIELD) && qSelector(NO_SELECTION).getAttribute(ARIA_HIDDEN) != true) {
clearInterval(waitForImagesInterval);
return imageUsingOCR();
} else {
//TODO: Identify Objects for the following (Ex: bed,chair,table etc)
//Ref for clothing: https://www.youtube.com/watch?v=yWwzFnAnrLM, https://www.youtube.com/watch?v=FiNglI1wRNk,https://www.youtube.com/watch?v=oHAkK_9UCQ8
var targetNodeList = ["Yes", "3 or more items of furniture", "Equipped space or room", "Photo is clean, no watermarks, logos or text overlays", "An interior photo of room", "Unsure", "Photo is sharp"];
for (var j = 0; j < targetNodeList.length; j++) {
var targetNode = Array.from(qSelectorAll('div'))
.find(el => el.textContent === targetNodeList[j]);
if (targetNode) {
//console.log("Target Node Found");
clearInterval(waitForImagesInterval);
return unsure(targetNodeList[j]);
}
}
}
}, 5000);
}
//TODO: Convert Image to base64 to avoid multiple calls
function preProcessImage(base64Image, imageUrl) {
//Darken and Brighten
Jimp.read(base64Image).then(function(data) {
data.color([
{
apply: 'darken',
params: [20]
}
]).color([
{
apply: 'brighten',
params: [20]
}
])
.greyscale()
.getBase64(Jimp.AUTO, function(err, src) {
var img = document.createElement("img");
img.setAttribute("src", src);
worker.recognize(img, LANGUAGE_FOR_OCR).then(function(data) {
//Remove Image After recognizing
img.removeAttribute("src");
//If null change to other methods
if (data && data.text && data.text.length > 0) {
inputChallenge(postProcessImage(data), imageUrl);
return selectImages();
} else {
preProcessImageMethod2(base64Image, imageUrl);
}
});
});
});
}
function preProcessImageMethod2(base64Image, trimageUrl) {
//Multi Contrast darken and brighten
Jimp.read(base64Image).then(function(data) {
data.color([
{
apply: 'darken',
params: [20]
}
]).contrast(1).color([
{
apply: 'brighten',
params: [20]
}
]).contrast(1).greyscale().getBase64(Jimp.AUTO, function(err, src) {
var img = document.createElement("img");
img.setAttribute("src", src);
worker.recognize(img, LANGUAGE_FOR_OCR).then(function(data) {
//Remove Image After recognizing
img.removeAttribute("src");
if (data && data.text && data.text.length > 0) {
inputChallenge(postProcessImage(data), imageUrl);
return selectImages();
} else {
preProcessImageMethod3(base64Image, imageUrl);
}
});
});
});
}
function preProcessImageMethod3(base64Image, imageUrl) {
//Multi Contrast only brighten
Jimp.read(base64Image).then(function(data) {
data.contrast(1).color([{
apply: 'brighten',
params: [20]
}
])
.contrast(1)
.greyscale()
.getBase64(Jimp.AUTO, function(err, src) {
var img = document.createElement("img");
img.setAttribute("src", src);
worker.recognize(img, LANGUAGE_FOR_OCR).then(function(data) {
//Remove Image After recognizing
img.removeAttribute("src");
if (data && data.text && data.text.length > 0) {
inputChallenge(postProcessImage(data), imageUrl);
return selectImages();
} else {
preProcessImageMethod4(base64Image, imageUrl);
}
});
});
});
}
function preProcessImageMethod4(base64Image, imageUrl) {
//Resize the image
Jimp.read(base64Image).then(function(data) {
data.resize(256, Jimp.AUTO)
.quality(60) // set JPEG quality
.greyscale() // set greyscale
.getBase64(Jimp.AUTO, function(err, src) {
var img = document.createElement("img");
img.setAttribute("src", src);
worker.recognize(img, LANGUAGE_FOR_OCR).then(function(data) {
//Remove Image After recognizing
img.removeAttribute("src");
inputChallenge(postProcessImage(data), imageUrl);
return selectImages();
});
});
});
}
function postProcessImage(data) {
var filterValues = ['\n', '{', '}', '[', ']'];
for (var i = 0; i < filterValues.length; i++) {
data.text = data.text.replaceAll(filterValues[i], "");
}
return data;
}
// Using Tesseract to recognize images
function imageUsingOCR() {
try {
//console.log("Image using OCR");
var urlString = qSelector(IMAGE_FOR_OCR).style.background;
var imageUrl = getUrlFromString(urlString);
if (imageUrl == 0) {
return selectImagesAfterDelay(1);
}
Jimp.read(imageUrl).then(function(data) {
data.getBase64(Jimp.AUTO, function(err, src) {
var img = document.createElement("img");
img.setAttribute("src", src);
var base64Image = img.src;
preProcessImage(base64Image, imageUrl);
})});
} catch (err) {
console.log(err.message);
return selectImagesAfterDelay(1);
}
}
async function convertTextToImage(text) {
//Convert Text to image
var canvas = document.createElement("canvas");
var textLength = text.length;
canvas.width = 60 * textLength;
canvas.height = 80;
var ctx = canvas.getContext('2d');
ctx.font = "30px Arial";
ctx.fillText(text, 10, 50);
var img = document.createElement("img");
img.src = canvas.toDataURL();
return img;
}
async function convertImageToText(img) {
await initializeTesseractWorker();
//Convert Image to Text
var text = "";
await worker.recognize(img, LANGUAGE_FOR_OCR).then(function(data) {
text = data.text;
// console.log("Recognized Text::" + text);
});
return text.trim();
}
function areExampleImageUrlsChanged() {
var prevExampleUrls = exampleImageList;
currentExampleUrls = [];
if (qSelectorAll(CHALLENGE_IMAGE).length > 0) {
for (let i = 0; i < qSelectorAll(CHALLENGE_IMAGE).length; i++) {
var urlString = qSelectorAll(CHALLENGE_IMAGE)[i].style.background;
var imageUrl = getUrlFromString(urlString);
if (imageUrl == 0) {
console.log("Image url is empty, Retrying...");
return true;
}
currentExampleUrls[i] = imageUrl;
}
}
if (prevExampleUrls.length != currentExampleUrls.length) {
return true;
}
for (let i = 0; i < currentExampleUrls.length; i++) {
if (prevExampleUrls[i] != currentExampleUrls[i]) {
return true;
}
}
return false;
}
async function identifyObjectsFromImages(imageUrlList) {
identifiedObjectsList = [];
for (let i = 0; i < imageUrlList.length; i++) {
try {
let img = new Image();
img.crossOrigin = "Anonymous";
img.src = imageUrlList[i];
img.onload = () => {
initializeTensorFlowModel().then(model => model.detect(img))
.then(function(predictions) {
let predictionslen = predictions.length;
let hashSet = new Set();
for (let j = 0; j < predictionslen; j++) {
hashSet.add(predictions[j].class);
}
hashSet.forEach((key) => {
identifiedObjectsList.push(key);
});
img.removeAttribute("src");
if (i == imageUrlList.length - 1) {
identifyObjectsFromImagesCompleted = true;
}
})
}
} catch (e) {
console.log(e);
}
}
}
async function identifyObjectsFromImagesUsingMobileNet(imageUrlList) {
identifiedObjectsList = [];
for (let i = 0; i < imageUrlList.length; i++) {
try {
let img = new Image();
img.crossOrigin = "Anonymous";
img.src = imageUrlList[i];
img.onload = () => {
initializeTensorFlowMobilenetModel().then(model => model.classify(img))
.then(function(predictions) {
let predictionslen = predictions.length;
let hashSet = new Set();
for (let j = 0; j < predictionslen; j++) {
if(predictions[j].className.includes(",")){
var multiPredictions = predictions[j].className.split(',');
for(let k=0; k< multiPredictions.length;k++){
hashSet.add(multiPredictions[k].trim());
}
}else{
hashSet.add(predictions[j].className);
}
}
hashSet.forEach((key) => {
identifiedObjectsList.push(key);
});
img.removeAttribute("src");
if (i == imageUrlList.length - 1) {
identifyObjectsFromImagesCompleted = true;
}
})
}
} catch (e) {
console.log(e);
}
}
}
async function getWordFromIdentifiedObjects(identifiedObjectsList) {
var hashMap = new Map();
for (var i = 0; i < identifiedObjectsList.length; i++) {
if (hashMap.has(identifiedObjectsList[i])) {
hashMap.set(identifiedObjectsList[i], hashMap.get(identifiedObjectsList[i]) + 1)
} else {
hashMap.set(identifiedObjectsList[i], 1)
}
}
var maxCount = 0,
objectKey = -1;
await hashMap.forEach((value, key) => {
if (maxCount < value && (key.equalsOneOf(TRANSPORT_TYPES) ||
key.equalsOneOf(LIVING_ROOM_TYPES) ||
key.equalsOneOf(ANIMAL_TYPES)|| key == VALLEY)) {
objectKey = key;
maxCount = value;
}
});
return objectKey;
}
function inputChallenge(data, imageUrl) {
try {
if ((qSelector(IMAGE_FOR_OCR).style.background).includes(imageUrl)) {
console.log(data.text);
var targetNode = qSelector(CHALLENGE_INPUT_FIELD);
targetNode.value = data.text.replaceAll("\n", "");
var challengeInput = qSelector(CHALLENGE_INPUT);
triggerEvent(challengeInput, 'input');
// Set a timeout if you want to see the text
qSelector(SUBMIT_BUTTON).click();
}
} catch (err) {
console.log(err.message);
}
}
async function identifyWordFromExamples() {
var word = -1;
if (areExampleImageUrlsChanged()) {
exampleImageList = currentExampleUrls;
if (exampleImageList.length == 0) {
return -1;
}
identifyObjectsFromImages(exampleImageList);
while (!identifyObjectsFromImagesCompleted) {
await delay(2000)
}
identifyObjectsFromImagesCompleted = false;
word = await getWordFromIdentifiedObjects(identifiedObjectsList);
//Word has not been identified yet, use mobile net to recognize images
if (word == -1) {
//Initialiaze MobileNet Model
await initializeTensorFlowMobilenetModel();
identifyObjectsFromImagesUsingMobileNet(exampleImageList);
while (!identifyObjectsFromImagesCompleted) {
await delay(2000)
}
identifyObjectsFromImagesCompleted = false;
word = getWordFromIdentifiedObjects(identifiedObjectsList);
}
return word;
} else {
return getWordFromIdentifiedObjects(identifiedObjectsList);
}
return word;
}
var prevObject = "";
function isObjectChanged() {
if (!prevObject && qSelector(PROMPT_TEXT)) {
prevObject = qSelector(PROMPT_TEXT).innerText;
return true;
}
if (prevObject && qSelector(PROMPT_TEXT) &&
prevObject == qSelector(PROMPT_TEXT).innerText) {
return false;
}
return true;
}
async function identifyWord() {
var word = -1;
try {
if (window.location.href.includes('&hl=en') || (ENABLE_DEFAULT_LANGUAGE && DEFAULT_LANGUAGE == LANG_ENGLISH)) {
word = qSelector(PROMPT_TEXT) ? qSelector(PROMPT_TEXT).innerText : word;
if (word && (word.includes(SENTENCE_TEXT_A) || word.includes(SENTENCE_TEXT_AN))) {
word = word.replace(SENTENCE_TEXT_A, '');
word = word.replace(SENTENCE_TEXT_AN, '');
}
if (word.equalsOneOf(TRANSPORT_TYPES) || word == VERTICAL_RIVER) {
return word;
} else {
//Using OCR on Text for accurate result
console.log("New word or different cyrillic");
var img = await convertTextToImage(word);
word = await convertImageToText(img);
word = word.replace(SENTENCE_TEXT_A, '');
word = word.replace(SENTENCE_TEXT_AN, '');
if (word.equalsOneOf(TRANSPORT_TYPES) || word == VERTICAL_RIVER) {
return word;
} else {
if(MATCH_IMAGES_USING_TRAINER){
word = qSelector(PROMPT_TEXT) ? qSelector(PROMPT_TEXT).innerText : -1;
if(word){
img = await convertTextToImage(word);
word = await convertImageToText(img);
}
return word;
}else{
word = await identifyWordFromExamples();
}
}
}
} else {
//If word is not english
//Identify Images from Example
word = await identifyWordFromExamples();
}
} catch (e) {
console.log(e);
}
return word;
}
var prevWord = "";
async function selectImages() {
if (ENABLE_DEFAULT_LANGUAGE) {
for (let i = 0; i < qSelectorAll(LANGUAGE_SELECTOR).length; i++) {
if (qSelectorAll(LANGUAGE_SELECTOR)[i].innerText == DEFAULT_LANGUAGE) {
document.querySelectorAll(LANGUAGE_SELECTOR)[i].click();
await delay(1000);
}
}
}
if (qSelectorAll(IMAGE) && qSelectorAll(IMAGE).length == 9 && qSelector(NO_SELECTION).getAttribute(ARIA_HIDDEN) != true) {
selectedImageCount = 0;
try {
if (isObjectChanged()) {
prevWord = await identifyWord();
}
var word = prevWord;
if (word == -1 && skipCount >= MAX_SKIPS) {
console.log("Max Retries Attempted. Captcha cannot be solved");
return;
} else if (word == -1 && skipCount < MAX_SKIPS) {
skipCount++;
if (qSelector(SUBMIT_BUTTON)) {
qSelector(SUBMIT_BUTTON).click();
}
return selectImagesAfterDelay(5);
} else {
//Get Synonyms for the word
word = await getSynonyms(word);
//console.log("words are::" + word);
}
} catch (err) {
console.log(err.message);
return selectImagesAfterDelay(5);
}
var imageList = [];
try {
imageList = getImageList();
if (imageList.length != 9) {
//console.log("Waiting");
// Image containers are visible but there are no urls in the image
// Skip the image
if (qSelector(SUBMIT_BUTTON)) {
qSelector(SUBMIT_BUTTON).click();
}
return selectImagesAfterDelay(5);
}
} catch (err) {
console.log(err.message);
return selectImagesAfterDelay(5);
}
//Identifying word for seaplane and matching images
//TODO: Refactor Code to combine different models or use only one model based on accuracy
if(word && word != -1 && MATCH_IMAGES_USING_TRAINER && NEW_WORD_IDENTIFIED){
for (let i = 0; i < 9; i++) {
matchImagesUsingTrainer(imageList[i], word, i);
}
}else if(word && word != -1 && USE_COLOUR_PATTERN){
for (let i = 0; i < 9; i++) {
matchImageForVerticalRiver(imageList[i], word, i);
}
}else if (word && word != -1 && USE_MOBILE_NET) {
for (let i = 0; i < 9; i++) {
matchImagesUsingTensorFlowMobileNet(imageList[i], word, i);
}
} else if (word && word != -1) {
for (var i = 0; i < 9; i++) {
if (ENABLE_TENSORFLOW) {
matchImagesUsingTensorFlow(imageList[i], word, i);
} else {
matchImages(imageList[i], word, i);
}
}
}
waitUntilImageSelection();
} else {
waitForImagesToAppear();
}
}
})();
@Ripomkahan
Copy link

I need update hcaptcha scripts, do you help me?

@dlashkevich
Copy link

Does it work? I don't see any progress with the solution.

@jishanshaikh4
Copy link
Author

Does it work? I don't see any progress with the solution.

What's the problem?

I need update hcaptcha scripts, do you help me?

This script is provided as is, in working condition. What update do you need?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment