Sunday, July 1, 2012

My Raspberry Pi Learnings

These are notes I made during my initial playing with my Raspberry PI.  All work was done from an Ubuntu desktop machine.

Excellent resources:

Got the Debian download from

Unzip and verify the SHA-1 hash:
  • cd /home/dave/Desktop
  • sudo wget
  • sudo unzip /home/dave/Desktop/
  • sudo cat /home/dave/Desktop/debian6-19-04-2012/debian6-19-04-2012.img.sha1
  • sudo sha1sum /home/dave/Desktop/debian6-19-04-2012/debian6-19-04-2012.img (the two strings these commands output should be identical)
Install the distro on a 32 GB SDHC card:
  • df -h - To show any mounted partitions that may exist on the SD card
  • sudo umount /dev/sdbX - To unmount any of the partitions found above
  • sudo dd if=/home/dave/Desktop/debian6-19-04-2012/debian6-19-04-2012.img of=/dev/sdb - To set up the SD card (be careful not to accidentally obliterate the partitions you are using to run your computer)
  • sudo sync - To ensure that all writing to the card is finished before removing it
Insert SD card into Raspberry PI board.  Make sure to use a high quality micro-USB cable because when using a cheap one the board did not get enough power and this caused the keyboard not to work and the board to crash after a short time.

Get a powered USB hub for all peripherals that is known to work with Raspberry PI (Verified Peripherals) because the whole setup is very sensitive to having sufficient power.

Post installation configuration:
  • Login with pi/raspberry credentials
  • Change password
  • Configure the timezone (sudo dpkg-reconfigure tzdata)
  • Update the firmware using instructions found at
  • Do Debian patches (sudo apt-get update, sudo apt-get upgradesudo apt-get dist-upgrade if necessary)
  • Edit config.txt (sudo nano /boot/config.txt) and add config_hdmi_boost=4 to increase the power output of the HDMI signal to overcome a blank screen when trying to run LXDE
  • Run LXDE (started with the command startx)
  • Run a command to prevent prompts for administrative credentials when using certain tools in the GUI (gconftool-2  --type bool  --set  /apps/gksu/sudo-mode  true)
  • Resize partitions to use the full capacity of the SD card using the instructions in this video (
  • Install Chromium Browser (sudo apt-get install chromium-browser)

Round-2 Setting up a media center

Decided to try raspbmc (  These instructions worked perfectly on an old 2GB SD card I had lying around.

Wednesday, September 21, 2011

Setting up OSSEC on Ubuntu 11.04


This blog post captures my experience installing and configuring OSSEC (host-based intrusion detection software).

OSSEC Installation

The basic process that was followed is outlined on the OSSEC website.

Get the main install package from the OSSEC download page.  The following are the commands to download the tarball and verify its integrity.  Ensure that the md5 and sha1 checksums match the strings stored in the downloaded checksum file.

  • wget
  • wget
  • cat ossec-hids-2.6_checksum.txt
  • md5sum ossec-hids-2.6.tar.gz
  • sha1sum ossec-hids-2.6.tar.gz
Commands to extract the tarball and delete the original downloads:
  • tar -xvvf ossec-hids-2.6.tar.gz
  • rm ossec-hids-2.6.tar.gz
  • rm ossec-hids-2.6_checksum.txt
Run the install script:
  • cd ossec-hids-2.6/
  • sudo ./
  • en - english
  • local - local installation of the server and agent
  • /var/ossec - where we want to install it
  • n - disable email notification
  • y - run integrity check daemon
  • y - run rootkit detection engine
  • y - enable active response
  • y - enable firewall-drop response
  • n - no more IPs to add to the active response white list
  • enter - builds OSSEC
At the end of the build process there are messages to indicate that the init script has been modified to start OSSEC HIDS during boot and that configuration has finished properly.  In addition the commands to start and stop OSSEC are displayed:
  • sudo /var/ossec/bin/ossec-control start 
  • sudo /var/ossec/bin/ossec-control stop
Start OSSEC using the above command.

Installing OSSEC-UI (Web-based user-interface for OSSEC)

This installation process is also posted on the OSSEC web site.  Another good resource can be found here.
Get the web interface install package from the OSSEC download page and verify it's integrity:
  • wget
  • wget
  • cat ossec-wui-0.3-checksum.txt
  • md5sum ossec-wui-0.3.tar.gz
  • sha1sum ossec-wui-0.3.tar.gz
Commands to extract the tarball and delete the original downloads:
  • tar -xvvf ossec-wui-0.3.tar.gz
  • rm ossec-wui-0.3.tar.gz
  • rm ossec-wui-0.3-checksum.txt
Move the extracted directory under the web root then change to that directory:
  • sudo mv ossec-wui-0.3/ /var/www/
  • cd /var/www/ossec-wui-0.3
Run the install script and configure some things:
  • sudo ./ 
  • enter the username and password of a new user for OSSEC
  • sudo nano /etc/group (change ossec:x:1004: to ossec:x:1004:www-data)
  • sudo chmod 770 tmp/
  • sudo chgrp www-data tmp/
  • sudo /etc/init.d/apache2 restart (restart apache)
Restrict public access to the /var/www/ossec-wui-0.3 directory by editing /etc/apache2/httpd.conf to contain the following:
   <Directory /var/www/ossec-wui-0.3/>
   Order allow,deny
   Allow from
   Allow from
Resolve issues with the deprecated ereg_replace function:
  • grep ereg_replace /var/www/ossec-wui-0.3/lib/*.php
  • edit all results returned; for example: ereg_replace(">" becomes str_replace("/>/g"
Resolve issue on line 842 of /var/www/ossec-wui-0.3/lib/os_lib_alerts.php:
  • remove the double quotes from fseek($fp, $seek_place, "SEEK_SET");
Configuring rules to ignore certain events is done by editing /home/ubuntu/ossec-hids-2.6/etc/rules/local_rules.xml so that it contains rules such as:
   <rule id="100551" level="0">
     <description>Ignore integrity checksum changed for MOTD.</description>

Wednesday, August 17, 2011

Web Application Testing Automation

Architecture Choices

We have chosen the following architecture for our web application testing:
  • Primary test client is a Windows 2003 server running in Amazon's EC2 environment which if fully patched and has Internet Explorer 8, and the latest versions of Google Chrome and Firefox.
  • SeleniumHQ with test scripts written in PHP since it is already a core technology that we used to build the site.
  • The suite of tests developed on the primary test client will be written in such a way that they can also be copied and run from Windows and Ubuntu Linux machines located outside of the Amazon environment.
  • In the future, testing will be expanded to include IE9 and possibly additional browsers and versions.
We feel this will give us a testing process with the following qualities:
  • Comprehensive testing capability
  • Cost Effective
  • Reliable
  • Accessible by many from anywhere
Sources for Inspirations, Ideas and getting started

Selenium Server Configuration

The following was captured during setup of the Selenium Server on the primary test client...

Before installing the Selenium Server we need to install a recent version of Java from

Now download Selenium Server (2.4.0) from the Selenium Downloads page and put it into a folder where you are likely to find should you need to down the road.

Create a batch file containing the following in the same folder that you put the Selenium Server jar file into:
java -jar selenium-server-standalone-2.4.0.jar -trustAllSSLCertificates 

Create a shortcut to the above batch file in a convenient location.  When the Selenium Server is running it will occupy a command window that can be shut down using Ctrl-C when you are done with it.

Install PHP
Download the zip file from and unzip it into C:\Program Files\PHP\.
Copy php.ini-development to php.ini.
C:\Program Files\PHP>copy php.ini-development php.ini
        1 file(s) copied.

Install PEAR
Make sure you install the latest version of PEAR by first replacing the C:\PROGRA~1\PHP\PEAR\go-pear.phar file with one obtained from  Your output may not look like mine because I ran mine twice, first with an out of date version of the PEAR installer.
C:\PROGRA~1\PHP>php PEAR\go-pear.phar

Are you installing a system-wide PEAR or a local copy?
(system|local) [system] :

Below is a suggested file layout for your new PEAR installation.  To
change individual locations, type the number in front of the
directory.  Type 'all' to change all of them or simply press Enter to
accept these locations.

 1. Installation base ($prefix)                   : C:\PROGRA~1\PHP
 2. Temporary directory for processing            : C:\PROGRA~1\PHP\tmp
 3. Temporary directory for downloads             : C:\PROGRA~1\PHP\tmp
 4. Binaries directory                            : C:\PROGRA~1\PHP
 5. PHP code directory ($php_dir)                 : C:\PROGRA~1\PHP\pear
 6. Documentation directory                       : C:\PROGRA~1\PHP\docs
 7. Data directory                                : C:\PROGRA~1\PHP\data
 8. User-modifiable configuration files directory : C:\PROGRA~1\PHP\cfg
 9. Public Web Files directory                    : C:\PROGRA~1\PHP\www
10. Tests directory                               : C:\PROGRA~1\PHP\tests
11. Name of configuration file                    : C:\WINDOWS\pear.ini
12. Path to CLI php.exe                           : C:\PROGRA~1\PHP

1-12, 'all' or Enter to continue:
Beginning install...
Configuration written to C:\WINDOWS\pear.ini...
Initialized registry...
Preparing to install...
installing phar://C:/Program Files/PHP/PEAR/go-pear.phar/PEAR/go-pear-tarballs/A
installing phar://C:/Program Files/PHP/PEAR/go-pear.phar/PEAR/go-pear-tarballs/C
installing phar://C:/Program Files/PHP/PEAR/go-pear.phar/PEAR/go-pear-tarballs/P
installing phar://C:/Program Files/PHP/PEAR/go-pear.phar/PEAR/go-pear-tarballs/S
installing phar://C:/Program Files/PHP/PEAR/go-pear.phar/PEAR/go-pear-tarballs/X
install ok: channel://
install ok: channel://
install ok: channel://
install ok: channel://
install ok: channel://
PEAR: Optional feature webinstaller available (PEAR's web-based installer)
PEAR: Optional feature gtkinstaller available (PEAR's PHP-GTK-based installer)
PEAR: Optional feature gtk2installer available (PEAR's PHP-GTK2-based installer)

PEAR: To install optional features use "pear install pear/PEAR#featurename"

** WARNING! Old version found at C:\PROGRA~1\PHP, please remove it or be sure to
 use the new c:\progra~1\php\pear.bat command

The 'pear' command is now at your service at c:\progra~1\php\pear.bat

** The 'pear' command is not currently in your PATH, so you need to
** use 'c:\progra~1\php\pear.bat' until you have added
** 'C:\PROGRA~1\PHP' to your PATH environment variable.

Run it without parameters to see the available actions, try 'pear list'
to see what packages are installed, or 'pear help' for help.

For more information about PEAR, see:

Thanks for using go-pear!

For convenience, a REG file is available under C:\PROGRA~1\PHPPEAR_ENV.reg .
This file creates ENV variables for the current user.

Double-click this file to add it to the current user registry.


Double-click C:\PROGRA~1\PHPPEAR_ENV.reg as instructed above.

Install PHPUnit

Issue the 4 commands highlighted below as instructed on  Again your output may be different because what I show below is not from a virgin install. I was only able to get the beta version to install without errors, hence the "-beta" at the end of the fourth command.

C:\PROGRA~1\PHP>pear channel-discover
Adding Channel "" succeeded
Discovery of channel "" succeeded

C:\PROGRA~1\PHP>pear channel-discover
Adding Channel "" succeeded
Discovery of channel "" succeeded

C:\PROGRA~1\PHP>pear channel-discover
Adding Channel "" succeeded
Discovery of channel "" succeeded

C:\PROGRA~1\PHP>pear install phpunit/PHPUnit-beta
phpunit/PHPUnit can optionally use PHP extension "curl"
phpunit/PHPUnit can optionally use PHP extension "dbus"
pear/HTTP_Request2 can optionally use PHP extension "curl"
pear/HTTP_Request2 can optionally use PHP extension "fileinfo"
pear/HTTP_Request2 can optionally use PHP extension "openssl"
downloading PHPUnit-3.5.14.tgz ...
Starting to download PHPUnit-3.5.14.tgz (118,697 bytes)
..........................done: 118,697 bytes
downloading XML_RPC2-1.1.1.tgz ...
Starting to download XML_RPC2-1.1.1.tgz (68,431 bytes)
...done: 68,431 bytes
downloading HTTP_Request2-2.0.0RC1.tgz ...
Starting to download HTTP_Request2-2.0.0RC1.tgz (95,353 bytes)
...done: 95,353 bytes
downloading Net_URL2-0.3.1.tgz ...
Starting to download Net_URL2-0.3.1.tgz (8,488 bytes)
...done: 8,488 bytes
install ok: channel://
install ok: channel://
install ok: channel://
install ok: channel://


Install Firefox and the Selenium IDE Add-On
Install Firefox ( and the Selenium IDE add-on for it (Tools=>Add-Ons, search for "Selenium IDE").  Version can be an issue.  You need to ensure that the end result is a version of Selenium IDE that supports exporting to PHPUnit.

Running Tests
The following file is named IWA_Test.php which is located in the "H:\Program Files\PHP\" directory and was created largely by collecting and editing code snippets recorded in the Firefox Selenium IDE add-on.  This example runs tests on Chrome, Firefox and IE7.  Make sure you start the  Selenium Server before running the tests.  Run the tests in a command session from the above mentioned directory by typing "phpunit IWA_Test.php".


// Run from DOS prompt using:  phpunit IWA_Test.php //

  require_once 'PHPUnit\Extensions\SeleniumTestCase.php';

  class WebTest extends PHPUnit_Extensions_SeleniumTestCase {

    // Set up the browsers that we want to test in
    public static $browsers = array(
        'name'    => 'Google Chrome on Windows',
        'browser' => '*googlechrome H:\Documents and Settings\dave\Local Settings\Application Data\Google\Chrome\Application\chrome.exe',
        'host'    => 'localhost',
        'port'    => 4444,
        'timeout' => 30000,
        'name'    => 'Firefox on Windows',
        'browser' => '*firefox H:\Progra~1\Mozill~1\firefox.exe',
        'host'    => 'localhost',
        'port'    => 4444,
        'timeout' => 30000,
        'name'    => 'Internet Explorer 7 on Windows',
        'browser' => '*iexplore',
        'host'    => 'localhost',
        'port'    => 4444,
        'timeout' => 30000,

    protected function setUp() {

    public function test_IWA() {
      // Determine which browser is being tested //
      $tmp = serialize($this);
      $chrome_pos   = strpos($tmp, 'Google Chrome on Windows');
      $firefox_pos  = strpos($tmp, 'Firefox on Windows');
      $iexplore_pos = strpos($tmp, 'Internet Explorer 7 on Windows');
      if($chrome_pos   < $firefox_pos && $chrome_pos   < $iexplore_pos) { $curBrowser = 'GoogleChrome'; }
      if($firefox_pos  < $chrome_pos  && $firefox_pos  < $iexplore_pos) { $curBrowser = 'Firefox'; }
      if($iexplore_pos < $firefox_pos && $iexplore_pos < $chrome_pos)   { $curBrowser = 'IE7'; }

      echo PHP_EOL.PHP_EOL.PHP_EOL.'============== '.$curBrowser.' ==============='.PHP_EOL.PHP_EOL.PHP_EOL;

      // Request Account //
      echo '  Request Account...'.PHP_EOL;
      // Build a testUser with a name that should be unique
      $testUser = $curBrowser."_".date('dHis');
      $this->type("css=input[name=user_name]", $testUser);
      $this->type("css=input[name=first_name]", $testUser);
      $this->type("css=input[name=last_name]", $testUser);
      $this->type("css=input[name=email]", $testUser."");
      $this->type("phone_number", "123-456-7890");
      $this->type("password", "9/3=Two_");
      $this->type("password2", "9/3=Two_");
      $this->fireEvent("password2", "keyup");
      for ($second = 0; ; $second++) {
        if ($second >= 60) $this->fail("timeout");
        try {
          if ($this->isElementPresent("css=select[name=company]")) break;
        catch (Exception $e) {}
      $this->select("css=select[name=company]", "");
      $this->type("css=input[name=selected_comp]", '');
      $this->select("timezone", "label=-04:00 ==> Eastern Daylight Time");
      $this->fireEvent("css=input[name=user_name]",  "blur");
      $this->assertTrue($this->isTextPresent("exact:Getting Started"));
      $this->assertTrue($this->isTextPresent("exact:When is Dave available?"));

      // Login //
      echo '  Login...'.PHP_EOL;
      $this->type("user_name", $testUser);
      $this->type("password", "9/3=Two_");
      $this->assertTrue($this->isTextPresent("Getting Started"));

      // Edit Profile //
      echo '  Edit Profile...'.PHP_EOL;
      // Change every value
      $this->type("firstname", $testUser."x");
      $this->type("css=input[name=last_name]", $testUser."x");
      $this->type("css=input[name=email]", $testUser."@industrialwebapps.comx");
      $this->type("phone_number", "123-456-7890x");
      $this->select("timezone", "label=-08:00 ==> Pacific Standard Time");
      // Confirm that the changes were made
      $this->assertTrue($this->isTextPresent("Pacific Standard Time"));

      // Change Password //
      echo '  Change Password...'.PHP_EOL;
      $this->type("password", "6/2=Two+");
      $this->type("password2", "6/2=Two+");
      $this->fireEvent("password", "keyup");
      $this->fireEvent("password2", "keyup");
      $this->assertTrue($this->isTextPresent("exact:Password Change"));
      $this->assertTrue($this->isTextPresent("exact:Password successfully changed."));
      $this->assertTrue($this->isTextPresent("exact:A password change notification has been sent to your configured email address."));
      $this->assertTrue($this->isTextPresent("exact:When is Dave available?"));

      // Logout //
      echo '  Logout...'.PHP_EOL;
      $this->assertTrue($this->isTextPresent("exact:User Login"));
      $this->assertTrue($this->isTextPresent("exact:When is Dave available?"));



Sunday, August 14, 2011

Cancel file upload to iframe

This was a lot more difficult to find that I thought it would be so I'll capture it here in the hopes that is helps us (or anyone else) next time it is needed.

Situation: We use a hidden iframe as the target of the form that we are doing a file upload from. The contribution to this post by Steve Wasiura is what finally got me unstuck.

$('button#cancelUpload').click(function() {
    var amfIfrm = document.getElementById('amf_ifr');
    if($.browser.msie) { // Internet Explorer
    } else { // Other browsers

Thursday, August 11, 2011

Tablesorter custom parser for date format "d-mmm-yyyy h:mm:ss A"

I now need to sort full timestamps in my preferred format so needed another parser the handle dates like:
    "2-Mar-2010 2:12:13 PM".

var months = {};
    months["JAN"] = "01";
    months["FEB"] = "02";
    months["MAR"] = "03";
    months["APR"] = "04";
    months["MAY"] = "05";
    months["JUN"] = "06";
    months["JUL"] = "07";
    months["AUG"] = "08";
    months["SEP"] = "09";
    months["OCT"] = "10";
    months["NOV"] = "11";
    months["DEC"] = "12"; 
      id: 'drbDateLong',
      is: function(s) { return false; }, 
      format: function(s) {
        s = '' + s; //Make sure it's a string
        //                  d(1-31) - mmm(Jan-Dec) - yyyy    h(1-12):  mm   :  ss     AM/PM 
        var hit = s.match(/(\d{1,2})-([A-Za-z]{3})-(\d{4}) (\d{1,2}):(\d{2}):(\d{2}) ([A-Za-z]{2})/);
        if (hit && hit.length == 8) {
          if(hit[1].length == 1) { hit[1] = "0"+hit[1]; }
          if(hit[7].toUpperCase() == "PM") { hit[4] = String(parseInt(hit[4])+12); }
          if(hit[4].length == 1) { hit[4] = "0"+hit[4]; }
          return hit[3]+months[hit[2].toUpperCase()]+hit[1]+hit[4]+hit[5]+hit[6];
        } else { return s; }
      type: 'text'

Again, many thanks to Christian Bach and this post by MorningZ.

Monday, August 1, 2011

Tablesorter modification to handle checkboxes

Needing to sort tables that contain checkboxes is a relatively common need but despite this I was not able to find a custom developed parser for tablesorter so I rolled my own.

  id: 'checkbox',
  is: function(s) { return false; },
  format: function(s, table, cell) { return $(cell).find('input[type*=checkbox]').is(':checked'); }, 
  type: 'numeric'

Monday, July 25, 2011

Tablesorter modification to handle D-MMM-YYYY date format

I have a strong preference when it comes to date formats and that is D-MMM-YYYY. By using the 3 character abbreviation for the month and a four digit year it is impossible to misinterpret any date.

Our website makes routine use of Christian Bach's tablesorter but by default it does not handle my preferred date format.  Adding the following code resolved this issue:
    var months = {}; 
    months["JAN"] = "01"; 
    months["FEB"] = "02"; 
    months["MAR"] = "03"; 
    months["APR"] = "04"; 
    months["MAY"] = "05"; 
    months["JUN"] = "06"; 
    months["JUL"] = "07"; 
    months["AUG"] = "08"; 
    months["SEP"] = "09"; 
    months["OCT"] = "10"; 
    months["NOV"] = "11"; 
    months["DEC"] = "12";  
        id: 'drbDate', 
        is: function(s) { return false; },  
            format: function(s) { 
              s = '' + s; //Make sure it's a string 
              //                  d(1-31) - mmm(Jan-Dec) - yyyy 
              var hit = s.match(/(\d{1,2})-([A-Za-z]{3})-(\d{4})/); 
              if (hit && hit.length == 4) { 
                if(hit[1].length == 1) { hit[1] = "0"+hit[1]; } 
                return hit[3]+months[hit[2].toUpperCase()]+hit[1]; 
              } else { return s; } 
            }, type: 'text' 

Many thanks to Christian Bach and this post by MorningZ.