removed eronius comment
[ga4php.git] / lib / ga4php.php
index 8bc5946..22a7b2c 100644 (file)
@@ -2,9 +2,25 @@
 
 abstract class GoogleAuthenticator {
        
-       function __construct() {
+       function __construct($totpskew=1, $hotpskew=10, $hotphuntvalue=200000) {
+               // the hotpskew is how many tokens forward we look to find the input
+               // code the user used
+               $this->hotpSkew = $hotpskew;
+               
+               // the totpskew value is how many tokens either side of the current
+               // token we should check, based on a time skew.
+               $this->totpSkew = $totpskew;
+               
+               // the hotphuntvalue is what we use to resync tokens.
+               // when a user resyncs, we search from 0 to $hutphutvalue to find
+               // the two token codes the user has entered - 200000 seems like overkill
+               // really as i cant imagine any token out there would ever make it
+               // past 200000 token code requests.
+               $this->hotpHuntValue = $hotphuntvalue;
        }
        
+       // pure abstract functions that need to be overloaded when
+       // creating a sub class
        abstract function getData($username);
        abstract function putData($username, $data);
        abstract function getUsers();
@@ -16,11 +32,27 @@ abstract class GoogleAuthenticator {
                $data["tokentimer"] = 30; // the token timer (For totp) and not supported by ga yet             
                $data["tokencounter"] = 1; // the token counter for hotp
                $data["tokenalgorithm"] = "SHA1"; // the token algorithm (not supported by ga yet)
+               $data["user"] = ""; // a place for implementors to store their own data
                
                return $data;
        }
        
-       // an internal funciton to get 
+       // custom data field manipulation bits
+       function setCustomData($username, $data) {
+               $data = $this->internalGetData($username);
+               $data["user"] = $key;
+               $this->internalPutData($username, $data);
+       }
+       
+       function getCustomData($username) {
+               $data = $this->internalGetData($username);
+               $custom = $data["user"];
+               return $custom;
+               
+       }
+       
+       // an internal funciton to get data from the overloaded functions
+       // and turn them into php arrays.
        function internalGetData($username) {
                $data = $this->getData($username);
                $deco = unserialize(base64_decode($data));
@@ -32,9 +64,11 @@ abstract class GoogleAuthenticator {
                return $deco;
        }
        
-
+       // the function used inside the class to put the data into the
+       // datastore using the overloaded data saving class
        function internalPutData($username, $data) {
-               $enco = base64_encode(serialize($data));
+               if($data == "") $enco = "";
+               else $enco = base64_encode(serialize($data));
                
                return $this->putData($username, $enco);
        }
@@ -45,21 +79,22 @@ abstract class GoogleAuthenticator {
        // so lets not be able to set that yet
        function setTokenType($username, $tokentype) {
                $tokentype = strtoupper($tokentype);
-               if($tokentype!="HOTP" and $tokentype!="TOTP") {
+               if($tokentype!="HOTP" && $tokentype!="TOTP") {
                        $errorText = "Invalid Token Type";
                        return false;
                }
                
                $data = $this->internalGetData($username);
                $data["tokentype"] = $tokentype;
-               $this->internalPutData($username, $data);
+               return $this->internalPutData($username, $data);
                
-               return true;    
        }
        
        
        // create "user" with insert
        function setUser($username, $ttype="HOTP", $key = "", $hexkey="") {
+               $ttype  = strtoupper($ttype);
+               if($ttype != "HOTP" && $ttype !="TOTP") return false;
                if($key == "") $key = $this->createBase32Key();
                $hkey = $this->helperb322hex($key);
                if($hexkey != "") $hkey = $hexkey;
@@ -68,11 +103,13 @@ abstract class GoogleAuthenticator {
                $token["tokenkey"] = $hkey;
                $token["tokentype"] = $ttype;
                
-               $this->internalPutData($username, $token);              
+               if(!$this->internalPutData($username, $token)) {
+                       return false;
+               }               
                return $key;
        }
        
-       
+       // a function to determine if the user has an actual token
        function hasToken($username) {
                $token = $this->internalGetData($username);
                // TODO: change this to a pattern match for an actual key
@@ -89,27 +126,30 @@ abstract class GoogleAuthenticator {
                // consider scrapping this
                $token = $this->internalGetData($username);
                $token["tokenkey"] = $key;
-               $this->internalPutData($username, $token);              
+               $this->internalPutData($username, $token);
+               
+               // TODO error checking
+               return true;
        }
        
        
        // self explanitory?
        function deleteUser($username) {
                // oh, we need to figure out how to do thi?
-               $data = $this->internalGetData($username);
-               $data["tokenkey"] = "";
-               $this->internalPutData($username);              
+               $this->internalPutData($username, "");          
        }
        
+
+       
        // user has input their user name and some code, authenticate
        // it
        function authenticateUser($username, $code) {
 
                if(preg_match("/[0-9][0-9][0-9][0-9][0-9][0-9]/",$code)<1) return false;
-               error_log("begin auth user");
+               //error_log("begin auth user");
                $tokendata = $this->internalGetData($username);
-               $asdf = print_r($tokendata, true);
-               error_log("dat is $asdf");
+               //$asdf = print_r($tokendata, true);
+               //error_log("dat is $asdf");
                
                if($tokendata["tokenkey"] == "") {
                        $errorText = "No Assigned Token";
@@ -121,16 +161,16 @@ abstract class GoogleAuthenticator {
                $tlid = $tokendata["tokencounter"];
                $tkey = $tokendata["tokenkey"];
                
-               $asdf = print_r($tokendata, true);
-               error_log("dat is $asdf");
+               //$asdf = print_r($tokendata, true);
+               //error_log("dat is $asdf");
                switch($ttype) {
                        case "HOTP":
                                error_log("in hotp");
-                               $st = $tlid;
-                               $en = $tlid+20;
+                               $st = $tlid+1;
+                               $en = $tlid+$this->hotpSkew;
                                for($i=$st; $i<$en; $i++) {
                                        $stest = $this->oath_hotp($tkey, $i);
-                                       error_log("testing code: $code, $stest, $tkey, $tid");
+                                       //error_log("testing code: $code, $stest, $tkey, $tid");
                                        if($code == $stest) {
                                                $tokendata["tokencounter"] = $i;
                                                $this->internalPutData($username, $tokendata);
@@ -142,10 +182,10 @@ abstract class GoogleAuthenticator {
                        case "TOTP":
                                error_log("in totp");
                                $t_now = time();
-                               $t_ear = $t_now - 45;
-                               $t_lat = $t_now + 60;
-                               $t_st = ((int)($t_ear/30));
-                               $t_en = ((int)($t_lat/30));
+                               $t_ear = $t_now - ($this->totpSkew*$tokendata["tokentimer"]);
+                               $t_lat = $t_now + ($this->totpSkew*$tokendata["tokentimer"]);
+                               $t_st = ((int)($t_ear/$tokendata["tokentimer"]));
+                               $t_en = ((int)($t_lat/$tokendata["tokentimer"]));
                                //error_log("kmac: $t_now, $t_ear, $t_lat, $t_st, $t_en");
                                for($i=$t_st; $i<=$t_en; $i++) {
                                        $stest = $this->oath_hotp($tkey, $i);
@@ -156,7 +196,7 @@ abstract class GoogleAuthenticator {
                                }
                                break;
                        default:
-                               echo "how the frig did i end up here?";
+                               return false;
                }
                
                return false;
@@ -175,7 +215,7 @@ abstract class GoogleAuthenticator {
                // for keys
                
                //              $this->dbConnector->query('CREATE TABLE "tokens" ("token_id" INTEGER PRIMARY KEY AUTOINCREMENT,"token_key" TEXT NOT NULL, "token_type" TEXT NOT NULL, "token_lastid" INTEGER NOT NULL)');
-               $tokendata = internalGetData($username);
+               $tokendata = $this->internalGetData($username);
                
                // TODO: check return value
                $ttype = $tokendata["tokentype"];
@@ -190,7 +230,7 @@ abstract class GoogleAuthenticator {
                switch($ttype) {
                        case "HOTP":
                                $st = 0;
-                               $en = 200000;
+                               $en = $this->hotpHuntValue;
                                for($i=$st; $i<$en; $i++) {
                                        $stest = $this->oath_hotp($tkey, $i);
                                        //echo "code: $code, $stest, $tkey\n";
@@ -198,7 +238,7 @@ abstract class GoogleAuthenticator {
                                                $stest2 = $this->oath_hotp($tkey, $i+1);
                                                if($code2 == $stest2) {
                                                        $tokendata["tokencounter"] = $i+1;
-                                                       internalPutData($username, $tokendata);                                         
+                                                       $this->internalPutData($username, $tokendata);                                          
                                                        return true;
                                                }
                                        }
@@ -206,6 +246,7 @@ abstract class GoogleAuthenticator {
                                return false;
                                break;
                        case "TOTP":
+                               // ignore it?
                                break;
                        default:
                                echo "how the frig did i end up here?";
@@ -225,9 +266,13 @@ abstract class GoogleAuthenticator {
                $data = $this->internalGetData($user);
                $toktype = $data["tokentype"];
                $key = $this->helperhex2b32($data["tokenkey"]);
+
+               // token counter should be one more then current token value, otherwise
+               // it gets confused
+               $counter = $data["tokencounter"]+1;
                $toktype = strtolower($toktype);
                if($toktype == "hotp") {
-                       $url = "otpauth://$toktype/$user?secret=$key&counter=1";
+                       $url = "otpauth://$toktype/$user?secret=$key&counter=$counter";
                } else {
                        $url = "otpauth://$toktype/$user?secret=$key";
                }
@@ -265,6 +310,7 @@ abstract class GoogleAuthenticator {
        }
        
        
+       // TODO: lots of error checking goes in here
        function helperb322hex($b32) {
         $alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
 
@@ -295,6 +341,7 @@ abstract class GoogleAuthenticator {
         return $out2;
        }
        
+       // TODO: lots of error checking goes in here
        function helperhex2b32($hex) {
         $alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
 
@@ -318,6 +365,10 @@ abstract class GoogleAuthenticator {
         return $out2;
        }
        
+       // i've put alot of faith in the code from the
+       // php site's examples for the hash_hmac algorithm
+       // i assume its mostly correct but i should do
+       // some testing to verify this is actually the case
        function oath_hotp($key, $counter)
        {
                $key = pack("H*", $key);
@@ -339,6 +390,7 @@ abstract class GoogleAuthenticator {
            return str_pad($this->oath_truncate($hash), 6, "0", STR_PAD_LEFT);
        }
        
+       
        function oath_truncate($hash, $length = 6)
        {
            // Convert to dec
@@ -367,6 +419,12 @@ abstract class GoogleAuthenticator {
        private $errorText;
        private $errorCode;
        
+       private $hotpSkew;
+       private $totpSkew;
+       
+       private $hotpHuntValue;
+       
+       
        /*
         * error codes
         * 1: Auth Failed