Topic: Validations are old

Most of the FIs on the website seem to be validated around Nov/Dec 2009.

Jesse: Have you stopped running automated validations on these FIs?
Is there any way you could share code or tip/trick on how to validate these?

Re: Validations are old

I've been busy working on other projects and haven't checked back here in a while.  Sorry for the delay.

It seems like it was getting hung on one institution and could not reach the rest.  I added a timeout to the curl download and we're back in business.

Re: Validations are old

Hi Jesse,

Excellent site, I'm glad I found it.  It looks like the validation script isn't running again?  For example:

http://www.ofxhome.com/index.php/institution/view/500

Does not look like it has been validated since 2009...

Also, what is being validated?  Are you just testing that you can connect to the server?

Thanks.

Re: Validations are old

Hi Beiley,

What happened was that my hosting company moved OFX Home to a different server.  The environment was different in some respects so I have been fixing bugs as I can.  I just disabled debug mode so updates to validation should now continue.

I check for a few things:

1) The OFX server has a valid SSL certificate, and who they are registered with
2) If I send an OFX request it must respond with something that looks like OFX

Re: Validations are old

Hi Jesse,

Would you mind sharing your code for the validation script? Thanks.

Kuppa

Re: Validations are old

I don't see why not.

<?php

define('SUCCESS', 0);
define('FAIL_INVALID_URL', 1);
define('FAIL_INVALID_HTML', 2);
define('FAIL_INVALID_OFX', 3);
define('FAIL_INVALID_CN', 4);
define('FAIL_INVALID_SSL', 5);

function ReceiveData($ch, $data)
{
    GLOBAL $f;

    $f .= $data;

    return strlen($data);
}

function SubValidateOfx($id, $url, $org, $type)
{
    GLOBAL $f;
    $f = '';

    $now = strftime("%Y%m%d%H%M%S") . ".000[-8:PST]";

    if ($type == 1)
    {
        // No type
        $data = "OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:0F7418F4-27DD-4ED1-968E-60D792642CA9

<OFX>
<SIGNONMSGSRQV1>
<SONRQ>
<DTCLIENT>$now
<USERID>test
<USERPASS>test
<LANGUAGE>ENG
<FI>
<ORG>$org
";
if ($id != '')
{
    $data .= "<FID>$id
";
}
$data .= "</FI>
<APPID>Money
<APPVER>1600
</SONRQ>
</SIGNONMSGSRQV1>
</OFX>";
    }
    else if ($type == 2)
    {
        // Bank sign on
        $data = "OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE

<OFX>
<SIGNONMSGSRQV1>
<SONRQ>
<DTCLIENT>$now
<USERID>test
<USERPASS>test
<LANGUAGE>ENG
<FI>
<ORG>$org
";
if ($id != '')
{
    $data .= "<FID>$id
";
}
$data .= "</FI>
<APPID>QWIN
<APPVER>0900
</SONRQ>
</SIGNONMSGSRQV1>
<BANKMSGSRQV1>
<STMTTRNRQ>
<TRNUID>23382938
<STMTRQ>
<BANKACCTFROM>
<BANKID>987654321
<ACCTID>098-121
<ACCTTYPE>SAVINGS
</BANKACCTFROM>
<INCTRAN>
<INCLUDE>Y
</INCTRAN>
</STMTRQ>
</STMTTRNRQ>
</BANKMSGSRQV1>
</OFX>";
    }
    else if ($type == 3)
    {
        // Investment account
        $data = "OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:7A0CDEBA-DE2B-493F-BABB-F507FDAC3027

<OFX>
<SIGNONMSGSRQV1>
<SONRQ>
<DTCLIENT>$now
<USERID>test
<USERPASS>test
<LANGUAGE>ENG
<FI>
<ORG>$org
";
if ($id != '')
{
    $data .= "<FID>$id
";
}
$data .= "</FI>
<APPID>Money
<APPVER>1600
</SONRQ>
</SIGNONMSGSRQV1>
<INVSTMTMSGSRQV1>
<INVSTMTTRNRQ>
<TRNUID>8CCCCD65-13AF-4464-8990-5A0E108ACA3E
<CLTCOOKIE>4
<INVSTMTRQ>
<INVACCTFROM>
<BROKERID>test
<ACCTID>test
</INVACCTFROM>
<INCTRAN>
<DTSTART>19000101
<INCLUDE>Y
</INCTRAN>
<INCOO>Y
<INCPOS>
<DTASOF>$now
<INCLUDE>Y
</INCPOS>
<INCBAL>Y
</INVSTMTRQ>
</INVSTMTTRNRQ>
</INVSTMTMSGSRQV1>
</OFX>";
    }
    else if ($type == 4)
    {
        // Account info request
        $data = "OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:0F7418F4-27DD-4ED1-968E-60D792642CA9

<OFX>
<SIGNONMSGSRQV1>
<SONRQ>
<DTCLIENT>$now
<USERID>test
<USERPASS>test
<LANGUAGE>ENG
<FI>
<ORG>$org
";
if ($id != '')
{
    $data .= "<FID>$id
";
}
$data .= "</FI>
<APPID>Money
<APPVER>1600
</SONRQ>
</SIGNONMSGSRQV1>
<SIGNUPMSGSRQV1>
<ACCTINFOTRNRQ>
<TRNUID>C0A84BC5-6332-4674-ACEF-6149F15423B5
<CLTCOOKIE>4
<ACCTINFORQ>
<DTACCTUP>19700101000000
</ACCTINFORQ>
</ACCTINFOTRNRQ>
</SIGNUPMSGSRQV1>
</OFX>";
    }

    $data = str_replace("\n", "\r\n", $data);
    //echo $data; exit;
    $ch = curl_init($url);

    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-type: application/x-ofx", "Accept: */*, application/x-ofx"));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'ReceiveData');
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);

    $status = curl_exec($ch);
    if (!$status)
    {
        //echo "Could not download ofx data: ", curl_error($ch), "\n";
        return FAIL_INVALID_URL;
    }

    GLOBAL $gOfxOutput;
    $gOfxOutput = $f;
    
    if (!$f)
    {
        /*echo "<textarea rows=\"6\" cols=\"60\">\n";
        echo "$data error: no data downloaded", curl_error($ch);
        echo "\n</textarea>";*/
        return FAIL_INVALID_HTML;
    }

    // Test for OFXHEADER: 100
    $found = strpos($f, 'OFXHEADER');
    if ($found === false)
    {
        //echo "<textarea rows=\"6\" cols=\"60\">$data No ofx header\n";
        //echo $f, '</textarea><br>';
        return FAIL_INVALID_OFX;
    }

    curl_close($ch);

    // OFX data found
    return SUCCESS;
}

function ValidateOfx($id, $url, $org)
{
    // Try getting OFX information in a few different ways
    $err = SubValidateOfx($id, $url, $org, 1);
    if ($err == SUCCESS)
    {
        return SUCCESS;
    }

    $err = SubValidateOfx($id, $url, $org, 2);
    if ($err == SUCCESS)
    {
        return SUCCESS;
    }
    
    $err = SubValidateOfx($id, $url, $org, 3);
    if ($err == SUCCESS)
    {
        return SUCCESS;
    }

    $err = SubValidateOfx($id, $url, $org, 4);
    if ($err == SUCCESS)
    {
        return SUCCESS;
    }

    return $err;
}

function ValidateSsl($url)
{
    // Get host from url
    $host = parse_url($url, PHP_URL_HOST);
    
    // Run openssl to get certificate information.  cat /dev/null forces
    // an end of file so openssl s_client closes
    exec("cat /dev/null | openssl s_client -connect $host:443", $out);
    $issuer = false;
    $subject = false;
    foreach ($out as $line)
    {
        // Find needed certificate info (issuer and subject fields)
        $parts = preg_split("/\/C=|\/ST=|\/L=|\/O=|\/OU=|\/CN=/", $line, -1, PREG_SPLIT_OFFSET_CAPTURE);
        if (count($parts) > 3 && (substr($parts[0][0], 0, 7) == 'issuer=' || substr($parts[0][0], 0, 8) == 'subject='))
        {
            //echo '<pre>'; print_r($parts);
            $r = array();
            foreach ($parts as $part)
            {
                $startTag = strrchr(substr($line, 0, $part[1]), '/');
                $tag = substr($startTag, 1, strlen($startTag) - 2);
                $r[$tag] = $part[0];
            }
            //print_r($r); echo '</pre>';
            if ($parts[0][0] == 'issuer=')
            {
                $issuer = $r;
            }
            else
            {
                $subject = $r;
            }
        }
    }
    
    if ($subject !== false && $issuer !== false)
    {
        /*echo "<pre>\n";
        print_r($issuer);
        print_r($subject);
        echo "</pre>\n";*/
        
        if (strtoupper($subject['CN']) != strtoupper($host))
        {
            echo "invalid CN ", $subject['CN'], " host\n";
            return FAIL_INVALID_CN;
        }
        
        // Set validation org
        $ci =& get_instance();
        $data = array(
            'sslIssuerOrg' => $issuer['O'],
            'sslSubjectOrg' => $subject['O']);
        $ci->db->where('fiUrl', $url);
        $ci->db->update('ofxList', $data);
    }
    else
    {
        return FAIL_INVALID_SSL;
    }
    
    return SUCCESS;
}

?>

Edited: Added code tags

Re: Validations are old

Perfect. Thank you very much.