newspaint

Documenting Problems That Were Difficult To Find The Answer To

Monthly Archives: May 2013

Sampling Pixels on Web Page Using PhantomJS

Concerned your website might be hacked and defaced? How do you protect against this? One way might be to get a “snapshot” of your webpage as an image and then test pixels to see if they match the colours you expect at particular static locations. Not perfect but you’ll know quickly if someone wasn’t subtle when replacing the front-page content.

The technique I propose is this:

  • load the web page
  • render to a base-64 string
  • load “about:blank”
  • dynamically add an image to the DOM
  • assign the base-64 string to the image
  • dynamically add a canvas to the DOM
  • draw the image to the canvas’ context
  • sample points from the canvas’ context

First things first: load the web page and render it to a base 64 string:

var system = require('system');
var page = require('webpage').create();
page.onResourceError = function(resourceError) {
    page.reason = resourceError.errorString;
    page.reason_url = resourceError.url;
};

page.viewportSize = {
    'width': 1000,
    'height': 768
};

page.onConsoleMessage = function(msg) {
    system.stderr.writeLine('console: ' + msg);
};

page.open(
    'http://www.google.com/',
    function (status) {
        if ( status !== 'success' ) {
            console.log(
                "Error opening url \"" + page.reason_url
                + "\": " + page.reason
            );
            phantom.exit( 1 );
            return;
        }

        // take snapshot after 2 seconds to allow page AJAX to run
        window.setTimeout(
            function () {
                var imgBase64 = page.renderBase64();
                check_image( imgBase64 ); // function defined below
            },
            2 * 1000 // give page 2 seconds to execute before render
        );
    }
);

Now we have our base-64 string. Before proceeding I recommend that the page gets cleared to a blank page (so that the tested page’s JavaScript can’t wreak havoc on our image test function):

page.open(
    'about:blank',
    function ( status ) {
        check_image( imgBase64 ); // function defined below
    }
);

The pixel checking code must be done in a page.evaluate() function call because it will be getting the page to run JavaScript:

function check_image_js( imgString ) {
    // returns hex colour in ttrrggbb format (tt is opacity)
    function get_color( context, x, y ) {
        // return 2-character hex string (0-255)
        function decToHex( dd ) {
            var hex = Number(dd).toString(16);
            hex = "00".substr( 0, 2 - hex.length ) + hex;
            return hex;
        }

        var imgd = context.getImageData( x, y, 1, 1 ).data;
        var colorstr = (
            decToHex( imgd[3] ) + decToHex( imgd[0] ) +
            decToHex( imgd[1] ) + decToHex( imgd[2] )
        );

        return colorstr;
    }

    // list of pixels to check
    var pixels = [
        { x: 272, y: 135, col: 'ff000000', desc: 'Black in title' },
        { x: 97, y: 9, col: 'ffffffff', desc: 'White in button' }
    ];

    // create canvas
    var canvas = document.createElement( 'canvas' );
    canvas.width = 1000;
    canvas.height = 768;
    var context = canvas.getContext( '2d' );
    
    // load image
    var img = new Image();
    img.onload = function () { context.drawImage( img, 0, 0 ); };
    img.src = "data:image/png;base64," + imgString;

    // give time for image to load
    window.setTimeout(
        function () {
            var problemDetected = false;

            console.log( "- doing pixels" );

            var idx;
            for ( idx = 0; idx < pixels.length; idx++ ) {
                var row = pixels[idx];

                var actual = get_color( context, row.x, row.y );
                if ( actual !== row.col ) {
                    problemDetected = true;
                    console.log( "ERROR mismatch: expected \"" + row.col + "\", got \"" + actual + "\" (ttrrggbb) for \"" + row.desc + "\" at (" + row.x + ", " + row.y + ")" );
                } else {
                    console.log( "  - matched colour \"" + actual + "\" (ttrrggbb) for \"" + row.desc + "\" at (" + row.x + ", " + row.y + ")" );
                }
            }
        }, 500
    );
}

// call check_image_js in page.evaluate sandbox
function check_image( imgString ) {
    page.evaluate(
        function ( callback, string ) {
            callback( string );
        },
        check_image_js,
        imgString
    );
}

VNC Viewer Unable To Connect To Mac VNC Server

I was using VNC-Viewer-5.0.5-Linux-x64 on a Linux Ubunutu 12.04 desktop but was getting the following error message:

VNC Viewer Error Connecting To Mac

VNC Viewer Error Connecting To Mac

.. that reads:

To connect to Apple Remote Desktop (10.4) or Screen Sharing/Remote Management (10.5 onwards) built-in to Mac OS X, turn on the ‘VNC viewers may control screen with password’ option.

I don’t actually have a solution to this yet. When I do I’ll blog the answer. I suspect it is because only client may be connected to the desktop at a time – but haven’t been able to confirm whether this is indeed true.

Cannot Get SuperUser In CyanogenMod 10.1 ADB Shell

I was having trouble. I wanted to activate the superuser account by typing “su” into the shell.

I would see the following:

1|shell@android:/data $ su
su
Permission denied

To get access I had to go Settings -> Developer options -> Root access -> Apps and ADB (by default it was set to Apps only).

After this su worked:

1|shell@android:/data $ su
su
shell@android:/data #

Getting Developer Options

Cannot find, in CyanogenMod 10.1, the developer options in settings? Is this driving you mad because you want to enable “USB debugging”?

Go to Settings -> About phone -> tap on “Build number” about 8 times. This will unlock the developer options.

How Long Does It Take To Get An Easycash Account From Halifax Bank?

An acquaintance of mine went into their local Halifax branch two Thursdays ago and applied (and was accepted, in-branch) for an Easycash account (Halifax’s basic bank account). This acquaintance was able to provide proof of identity and proof of residential address (through being named as an occupier on a mortgage with that same bank).

This acquaintance received their account details by mail exactly two calendar weeks later (two Thursdays later) – which is in line with what they were told to expect (5-10 working days).

The Visa Electron debit card will come later!

What Infuriates Me About Google Documents 2013

The ability to work “in the cloud” on documents has enormous potential benefits: always retaining a backup of a document, tracking changes, and sharing with others.

Google Documents, however, is incredibly immature and has such a long way to go before even vaguely approaching the functionality, reliability, and usefulness of Microsoft Word from over a decade ago.

Here I list some of my pet peeves with Google Documents and why it frustrates me that the company I’m presently contracted to uses this product by default:

Google Documents/Writer

Styles

There are only 6 styles you can choose from. None of which are suitable for formatting source code, for example. You cannot define your own styles! This severe inflexibility makes production of professional documents all but useless. What we have is a basic text editor with a few enhancements – not a word processor by any stretch of the imagination.

Pasting Text Bugs

Pasting text (such as source code) results in spaces turning into unwanted tabs that don’t align as desired.

Pasting Google Drawings

Pasting a drawing from Google Draw is a nightmare – you cannot resize a Google Draw image with text because the text doesn’t scale with the diagram.

Other

Actually I have a lot more that I will add. But when I encounter serious issues such as the above it destroys my mental workflow and I just take a walk – it is usually hours before I re-engage which is a serious hit to any company’s bottom line.