X-Git-Url: http://git.pjr.cc/?p=ga4php.git;a=blobdiff_plain;f=lib%2Flib.php;h=42bc5991cdcc467afc96435d11d340643178efa3;hp=262149f9cc2b2be20dd45071a01686f7a3dadfa2;hb=98a6dee8498b3472e6f8fa9989279dddf4b1eefa;hpb=9b2752526f9f4bfac4831eb61fa63edd60117f77 diff --git a/lib/lib.php b/lib/lib.php index 262149f..42bc599 100644 --- a/lib/lib.php +++ b/lib/lib.php @@ -1,64 +1,84 @@ dbConnector = new PDO("sqlite:$file"); - } catch(PDOException $exep) { - $this->errorText = $exep->getMessage(); - $this->dbConnector = false; - } - } else { - $this->setupDB($file); - } - - $this->dbFile = $file; + // $getDataFunction expects 1 argument which defines what data it wants + // and can be "userlist" or "usertoken:username" + // $putDataFunciton expects 2 arguments, $1 is data type, $2 is the data + // $1 can be "changetoken:username", "removetoken:username", $2 is the token + // data in some encoded form + // tokenDATA will be like HOTP;KEY;CID where CID is the current counter value + // why encode like this? i cant think of a good reason tbh, i should probably just + // use php's arry encoder functions + function __construct($getDataFunction, $putDataFunction) { + $this->putDataFunction = $putDataFunction; + $this->getDataFunction = $getDataFunction; } - // creates the database (tables); - function setupDB($file) { - - try { - $this->dbConnector = new PDO("sqlite:$file"); - } catch(PDOException $exep) { - $this->errorText = $exep->getMessage(); - $this->dbConnector = false; - } + abstract function getData($username); + abstract function putData($username, $data); + abstract function getUsers(); - // here we create some tables and stuff - $this->dbConnector->query('CREATE TABLE "users" ("user_id" INTEGER PRIMARY KEY AUTOINCREMENT,"user_name" TEXT NOT NULL,"user_tokenid" INTEGER)'); - $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)'); + // a function to create an empty data structure + function createEmptyData() { + $data["tokenkey"] = ""; // the token key + $data["tokentype"] = ""; // the token type + $data["tokentimer"] = ""; // the token timer (For totp) and not supported by ga yet + $data["tokencounter"] = ""; // the token counter for hotp + $data["tokenalgorithm"] = ""; // the token algorithm (not supported by ga yet) + + return $data; } - // creates "user" in the database and returns a url for - // the phone. If user already exists, this returns false - // if any error occurs, this returns false - function setupUser($username) { - $key = $this->createBase32Key(); + // an internal funciton to get + function internalGetData($username) { + $data = getData($username); + $deco = unserialize(base64_decode($data)); - // sql for inserting into db - $sql = "select * from users where user_name='$username'"; - $res = $this->dbConnector->query($sql); - - if($res->fetchCount()>0) { - $this->errorText = "User Already Exists, $username"; - return false; + if(!$deco) { + $deco = createEmptyData(); } - // and finally create 'em - $this->dbConnector->query("insert into tokens values (NULL, '$key', 'HOTP','0')"); - $id = $this->dbConnector->lastInsertID(); - $this->dbConnector->query("insert into users values (NULL, '$username', '$id')"); + return $deco; + } + - $url = $this->createURL($username, $key); + function internalPutData($username, $data) { + $enco = base64_encode(serialize($data)); - return $url; + return putData($username, $enco); } + // set the token type the user it going to use. // this defaults to HOTP - we only do 30s token // so lets not be able to set that yet @@ -68,118 +88,108 @@ class GoogleAuthenticator { return false; } - $sql = "select * from users where user_name='$username'"; - $res = $this->dbConnector->query($sql); - - foreach($res as $row) { - $tid = $row["user_tokenid"]; - } - - - // TODO MUST DO ERROR CHECK HERE, this line could be lethal - $sql = "update tokens set token_type='$tokentype' where token_id='$tid'"; + $data = getData($username); + $data["tokentype"] = $tokentype; + $func = $this->putDataFunction; + $func("settokentype", $put); return true; } // create "user" with insert - function createUser($username, $key) { - // sql for inserting into db - $sql = "select * from users where user_name='$username'"; - $res = $this->dbConnector->query($sql); - - //if($res) if($res->fetchCount()>0) { - //$this->errorText = "User Already Exists, $username"; - //return false; - //} - - // and finally create 'em - $this->dbConnector->query("insert into tokens values (NULL, '$key', 'HOTP', '0')"); - $id = $this->dbConnector->lastInsertID(); - $this->dbConnector->query("insert into users values (NULL, '$username', '$id')"); - - $url = $this->createURL($username, $key); - - return $url; - } - - // Replcate "user" in the database... All this really - // does is to replace the key for the user. Returns false - // if the user doesnt exist of the key is poop - function replaceUser($username) { - $key = $this->createBase32Key(); - - // delete the user - TODO, clean up auth tokens - $sql = "delete from users where user_name='$username'"; - $res = $this->dbConnector->query($sql); + function setUser($username, $key = "", $ttype="HOTP") { + if($key == "") $key = $this->createBase32Key(); + $hkey = $this->helperb322hex($key); - // sql for inserting into db - just making sure. - $sql = "select * from users where user_name='$username'"; - $res = $this->dbConnector->query($sql); - - if($res->fetchCount()>0) { - $this->errorText = "User Already Exists, $username"; - return false; - } + $token["username"] = $username; + $token["tokenkey"] = $hkey; + $token["tokentype"] = $ttype; - // and finally create 'em - $this->dbConnector->query("insert into tokens values (NULL, '$key', '0')"); - $id = $this->dbConnector->lastInsertID(); - $this->dbConnector->query("insert into users values (NULL, '$username', '$id')"); - - $url = $this->createURL($username, $key); + $func = $this->putDataFunction; + $func("setusertoken", $token); - return $url; + return $key; } + // sets the key for a user - this is assuming you dont want // to use one created by the application. returns false // if the key is invalid or the user doesn't exist. function setUserKey($username, $key) { - $sql = "select * from users where user_name='$username'"; - $res = $this->dbConnector->query($sql); - - foreach($res as $row) { - $tid = $row["user_tokenid"]; - } - - - // TODO MUST DO ERROR CHECK HERE, this line could be lethal - $sql = "update tokens set token_key='$key' where token_id='$tid'"; - - return true; + // consider scrapping this + } + + + // have user? + function userExists($username) { + // need to think about this } + // self explanitory? function deleteUser($username) { - $sql = "select * from users where user_name='$username'"; - $res = $this->dbConnector->query($sql); - - foreach($res as $row) { - $tid = $row["user_tokenid"]; - } - - - // TODO MUST DO ERROR CHECK HERE, this line could be lethal - $sql = "delete from tokens where token_id='$tid'"; - $this->dbConnector->query($sql); - - $sql = "delete from users where user_name='$username'"; - $this->dbConnector->query($sql); + $func = $this->putDataFunction; + $func("deleteusertoken", $username); } // user has input their user name and some code, authenticate // it function authenticateUser($username, $code) { - $sql = "select * from users where user_name='$username'"; - $res = $this->dbConnector->query($sql); - $tid = -1; - foreach($res as $row) { - $tid = $row["user_tokenid"]; + $func = $this->getDataFunction; + $tokendata = $func("gettoken", $username); + + // TODO: check return value + $ttype = $tokendata["tokentype"]; + $tlid = $tokendata["tokencounter"]; + $tkey = $tokendata["tokenkey"]; + switch($ttype) { + case "HOTP": + $st = $tlid; + $en = $tlid+20; + for($i=$st; $i<$en; $i++) { + $stest = $this->oath_hotp($tkey, $i); + //error_log("code: $code, $stest, $tkey, $tid"); + if($code == $stest) { + $tokenset["username"] = $username; + $tokenset["tokencounter"] = $i; + + $func = $this->putDataFunction; + $func("settokencounter", $tokenset); + return true; + } + } + return false; + break; + case "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)); + //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); + //error_log("code: $code, $stest, $tkey\n"); + if($code == $stest) { + return true; + } + } + break; + default: + echo "how the frig did i end up here?"; } + return false; + + } + + // this function allows a user to resync their key. If too + // many codes are called, we only check up to 20 codes in the future + // so if the user is at 21, they'll always fail. + function resyncCode($username, $code1, $code2) { + // here we'll go from 0 all the way thru to 200k.. if we cant find the code, so be it, they'll need a new one // for HOTP tokens we start at x and go to x+20 // for TOTP we go +/-1min TODO = remember that +/- 1min should @@ -188,29 +198,31 @@ class GoogleAuthenticator { // $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)'); - $sql = "select * from tokens where token_id='$tid'"; - $res = $this->dbConnector->query($sql); + $func = $this->getDataFunction; + $tokendata = $func("gettoken", $username); - $tkey = ""; - $ttype = ""; - $tlid = ""; - foreach($res as $row) { - $tkey = $row["token_key"]; - $ttype = $row["token_type"]; - $tlid = $row["token_lastid"]; - } + // TODO: check return value + $ttype = $tokendata["tokentype"]; + $tlid = $tokendata["tokencounter"]; + $tkey = $tokendata["tokenkey"]; switch($ttype) { case "HOTP": - $st = $tlid; - $en = $tlid+20; + $st = 0; + $en = 200000; for($i=$st; $i<$en; $i++) { $stest = $this->oath_hotp($tkey, $i); //echo "code: $code, $stest, $tkey\n"; - if($code == $stest) { - $sql = "update tokens set token_lastid='$i' where token_id='$tid'"; - $this->dbConnector->query($sql); - return true; + if($code1 == $stest) { + $stest2 = $this->oath_hotp($tkey, $i+1); + if($code2 == $stest2) { + $tokenset["username"] = $username; + $tokenset["tokencounter"] = $i+1; + + $func = $this->putDataFunction; + $func("settokencounter", $tokenset); + return true; + } } } return false; @@ -222,14 +234,7 @@ class GoogleAuthenticator { } return false; - - } - - // this function allows a user to resync their key. If too - // many codes are called, we only check up to 20 codes in the future - // so if the user is at 21, they'll always fail. - function resyncCode($username, $code1, $code2) { - + } // gets the error text associated with the last error @@ -238,9 +243,15 @@ class GoogleAuthenticator { } // create a url compatibile with google authenticator. - function createURL($user, $key) { - $url = "otpauth://totp/$user?secret=$key"; - echo "url: $url\n"; + function createURL($user, $key,$toktype = "HOTP") { + // oddity in the google authenticator... hotp needs to be lowercase. + $toktype = strtolower($toktype); + if($toktype == "hotp") { + $url = "otpauth://$toktype/$user?secret=$key&counter=1"; + } else { + $url = "otpauth://$toktype/$user?secret=$key"; + } + //echo "url: $url\n"; return $url; } @@ -329,7 +340,7 @@ class GoogleAuthenticator { // HMAC $hash = hash_hmac ('sha1', $bin_counter, $key); - return $this->oath_truncate($hash); + return str_pad($this->oath_truncate($hash), 6, "0", STR_PAD_LEFT); } function oath_truncate($hash, $length = 6) @@ -355,8 +366,8 @@ class GoogleAuthenticator { // some private data bits. + private $getDatafunction; + private $putDatafunction; private $errorText; - private $dbFile; - private $dbConnector; } ?> \ No newline at end of file