Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* vim: set sts=4 ts=4 et shiftwidth=4 : */
- var background = "#766649";
- function toHex(d) {
- var rgb = d.data[2] | (d.data[1] << 8) | (d.data[0] << 16);
- return '#' + (0x1000000 + rgb).toString(16).slice(1)
- }
- function findFirstPixelX(canvas) {
- var context = canvas.getContext("2d");
- for (var x = 0; x < canvas.width; x++) {
- for (var y = 0; y < canvas.height; y++) {
- var color = toHex(context.getImageData(x, y, 1, 1));
- if (color != "#ffffff") {
- return x;
- }
- }
- }
- }
- function findFirstPixelY(canvas) {
- var context = canvas.getContext("2d");
- for (var y = 0; y < canvas.height; y++) {
- for (var x = 0; x < canvas.width; x++) {
- var color = toHex(context.getImageData(x, y, 1, 1));
- if (color != "#ffffff") {
- return y;
- }
- }
- }
- }
- function drawSolution(width, height, x, y, number, fontSize, clear) {
- var canvas = document.createElement("canvas");
- canvas.width = width;
- canvas.height = height;
- var ctx = canvas.getContext("2d");
- if (clear) {
- ctx.fillStyle = "#ffffff";
- ctx.fillRect(0, 0, canvas.width, canvas.height);
- }
- ctx.fillStyle = "#000000";
- ctx.font = "bold " + fontSize + "px Georgia";
- ctx.textBaseline="hanging";
- ctx.fillText(number, x, y);
- return { "canvas": canvas, width: ctx.measureText(number).width };
- }
- function rateSolution(original, guess, x, dx) {
- /* Compare pixels in original and guess in a box from x to x + dx */
- var ctx1 = original.getContext("2d");
- var ctx2 = guess.getContext("2d");
- var count = 0;
- for (var i = x; i < x + dx; i++) {
- for (var j = 0; j < original.height; j++) {
- var c1 = toHex(ctx1.getImageData(i, j, 1, 1));
- var c2 = toHex(ctx2.getImageData(i, j, 1, 1));
- /* Ignore background */
- if ((c1 == "#ffffff") && (c2 == "#ffffff")) {
- continue;
- }
- /* If both are the same, that's best */
- if (c1 == c2) {
- count += 5;
- continue;
- }
- /* If neither is a background pixel thats good */
- if ((c1 != "#ffffff") && (c2 != "#ffffff")) {
- count += 1;
- continue;
- }
- /* If original is a background pixel and guess is not, that's bad */
- if ((c1 == "#ffffff") && (c2 != "#ffffff")) {
- count -= 2;
- continue;
- }
- /* The other way around I am not sure... */
- if ((c1 != "#ffffff") && (c2 == "#ffffff")) {
- continue;
- }
- }
- }
- return count;
- }
- function guessDigit(original, x, y) {
- var result = {
- rating: 0
- };
- for (var i = 0; i < 10; i++) { // Digits
- for (var dy = 0; dy <= 5; dy++) { // Y-Postion range
- for (var dx = -2; dx < 3; dx++) { // X-Position range
- for (var fontSize = 12; fontSize < 18; fontSize++) { // Font size range
- var tmp = drawSolution(original.width, original.height, x + dx, y + dy, i, fontSize, true);
- var rating = rateSolution(original, tmp.canvas, x, tmp.width);
- if (rating > result.rating) {
- result.rating = rating;
- result.guess = i;
- result.width = tmp.width;
- result.x = x + dx;
- result.y = y + dy;
- result.fontSize = fontSize;
- }
- }
- }
- }
- }
- return result;
- }
- class CaptchaSolver {
- constructor() {
- this.STORAGE_KEY = "cryptic_key";
- this.IMAGES_TO_USE = 3;
- }
- deserialize(cb) {
- var images = [];
- var tmp = sessionStorage.getItem(this.STORAGE_KEY);
- if (tmp == null) {
- cb(images);
- return;
- }
- tmp = JSON.parse(tmp);
- for (var i = 0; i < tmp.length; i++) {
- var img = document.createElement("img");
- $(img).on("load", function() {
- var canvas = document.createElement("canvas");
- var ctx = canvas.getContext("2d");
- canvas.width = this.width;
- canvas.height = this.height;
- ctx.drawImage(this, 0, 0);
- images.push(canvas);
- if (images.length == tmp.length) {
- cb(images);
- }
- });
- img.src = tmp[i];
- }
- }
- serialize(images) {
- var dataUrls = [];
- for (var i = 0; i < images.length; i++) {
- dataUrls.push(images[i].toDataURL());
- }
- sessionStorage.setItem(this.STORAGE_KEY, JSON.stringify(dataUrls));
- }
- getCurrentImage() {
- var canvas = document.createElement("canvas");
- var ctx = canvas.getContext("2d");
- var img = $("img[src*='secode.php']");
- canvas.width = img.width();
- canvas.height = img.height();
- ctx.drawImage(img.get(0), 0, 0);
- return canvas;
- }
- preProcess(images) {
- var canvas = document.createElement("canvas");
- var ctx = canvas.getContext("2d");
- canvas.width = images[0].width;
- canvas.height = images[0].height;
- ctx.fillStyle = "#ffffff";
- ctx.fillRect(0, 0, canvas.width, canvas.height);
- var ctx1 = images[0].getContext("2d");
- var ctx2 = images[1].getContext("2d");
- var ctx3 = images[2].getContext("2d");
- for (var x = 0; x < canvas.width; x++) {
- for (var y = 0; y < canvas.height; y++) {
- /* TODO: Rewrite this to use IMAGES_TO_USE instead of 3. */
- var color1 = toHex(ctx1.getImageData(x, y, 1, 1));
- var color2 = toHex(ctx2.getImageData(x, y, 1, 1));
- var color3 = toHex(ctx3.getImageData(x, y, 1, 1));
- /* Get rid of black border */
- if ((x == 0) || (y == 0) || (x == canvas.width - 1) || (y == canvas.height - 1)) {
- continue;
- }
- /* If a pixel is background color in any of the 3 images, get rid of it */
- if ((color1 == background) || (color2 == background) || (color3 == background)) {
- continue;
- }
- /* Any pixels that are not background and not black, must be subpixels of the font must be correct. Noise doesn't have subpixels. */
- if (color1 != "#000000") {
- ctx.fillStyle = color1;
- ctx.fillRect(x, y, 1, 1);
- continue;
- }
- if (color2 != "#000000") {
- ctx.fillStyle = color2;
- ctx.fillRect(x, y, 1, 1);
- continue;
- }
- if (color3 != "#000000") {
- ctx.fillStyle = color3;
- ctx.fillRect(x, y, 1, 1);
- continue;
- }
- /* If a pixel has the same color in all images, it's probably correct too. */
- if ((color1 == color2) && (color1 == color3)) {
- ctx.fillStyle = color1;
- ctx.fillRect(x, y, 1, 1);
- continue;
- }
- }
- }
- /* Apply a simple filter that gets rid of single pixels that are left over. */
- ctx.fillStyle = "#ffffff";
- for (var x = 0; x < canvas.width; x++) {
- for (var y = 0; y < canvas.height; y++) {
- var color = toHex(ctx.getImageData(x, y, 1, 1));
- if (color == "#ffffff") {
- continue;
- }
- var checks = [
- [0, 1],
- [-1, 0], [1, 0],
- [0, -1],
- ];
- var surroundingPixelsClear = true;
- for (var i = 0; i < checks.length; i++) {
- var color = toHex(ctx.getImageData(x + checks[i][0], y + checks[i][1], 1, 1));
- if (color != "#ffffff") {
- surroundingPixelsClear = false;
- break;
- }
- }
- if (surroundingPixelsClear) {
- ctx.fillRect(x, y, 1, 1);
- }
- }
- }
- return canvas;
- }
- _solve(canvas) {
- var x = findFirstPixelX(canvas);
- var y = findFirstPixelY(canvas);
- var guesses = [];
- var solution = "";
- /* We have up to 6 digits */
- for (var i = 0; i < 6; i++) {
- var guess = guessDigit(canvas, x, y);
- console.log(guess);
- if (guess.rating <= 10) {
- break;
- }
- guesses.push(guess);
- x = guess.x + guess.width;
- solution += guess.guess;
- }
- return solution;
- }
- solve() {
- /* Deserializing images from data urls is apparently a clusterfuck, work around it with a callback function. */
- var ctx = this;
- this.deserialize(function(images) {
- if (images.length < ctx.IMAGES_TO_USE) {
- images.push(ctx.getCurrentImage());
- if (images.length < ctx.IMAGES_TO_USE) {
- ctx.serialize(images);
- /* Reload after a while */
- setTimeout(function() { location.reload(); }, 2 * 1000);
- return;
- }
- }
- /* Images have been collected, attempt to solve and reset history. */
- sessionStorage.removeItem(ctx.STORAGE_KEY);
- var tmp = $("img[src*='secode.php']").parent();
- tmp.append("<br />");
- for (var i = 0; i < images.length; i++) {
- tmp.append(images[i]);
- }
- var preprocessed = ctx.preProcess(images);
- tmp.append("<br />");
- tmp.append(preprocessed);
- var solution = ctx._solve(preprocessed);
- console.log(solution);
- $("form[action*='botpros.php'] > input[name='mode']").val(solution);
- });
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement