diff --git a/lib/phpSec/Auth/Authy.php b/lib/phpSec/Auth/Authy.php index 17fb436..4b84015 100644 --- a/lib/phpSec/Auth/Authy.php +++ b/lib/phpSec/Auth/Authy.php @@ -35,6 +35,16 @@ class Authy { */ public $lastError = null; + /** + * Authy ID + */ + public $authyId; + + /** + * \phpSec\Core object + */ + private $psl; + /** * Server URLs. */ @@ -43,6 +53,16 @@ class Authy { 'sandbox' => 'http://sandbox-api.authy.com', ); + /** + * Constructor. + * + * @param \phpSec\Core $psl + * phpSec core Pimple container. + */ + public function __construct(\phpSec\Core $psl) { + $this->psl = $psl; + } + /** * Add a new Authy user and get the Authy ID. * @@ -55,11 +75,14 @@ class Authy { * @param string $countrycode * User countrycode. Defaults to 1 (USA). * + * @param string $uid + * User ID + * * @return mixed * Returns the users Authy ID on success or false on errors. * @see \phpSec\Auth\Authy::$lastError. */ - public function userNew($email, $cellphone, $countrycode = 1) { + public function userNew($email, $cellphone, $countrycode = 1, $uid) { $data = array( 'user[email]' => $email, @@ -83,8 +106,15 @@ public function userNew($email, $cellphone, $countrycode = 1) { return false; } - if(isset($result->user->id)) { - return $result->user->id; + if (isset($result->user->id)) { + $this->authyId = $result->user->id; + + $store['authyId'] = $this->authyId; + $storeId = $this->getStoreId($uid); + + $this->psl['store']->write('authy', $storeId, $store); + + return $this->authyId; } $this->lastError = 'AUTHY_SERVER_SAYS_NO'; return false; @@ -103,7 +133,11 @@ public function userNew($email, $cellphone, $countrycode = 1) { * Return true if a valid Authy token is supplied, false on any errors. * @see \phpSec\Auth\Authy::$lastError. */ - public function verify($authyId, $token) { + public function verify($authyId = null, $token) { + if (!isset($authyId)) { + $authyId = $this->authyId; + } + $data = array( 'token' => $token, 'authy_id' => $authyId, @@ -249,4 +283,29 @@ private function apiCall($action, $data) { return json_decode($result); } + + /** + * Loads an authy entry from the database + * + * @param string $uid + * The user ID + * + * @return string + * Authy ID + */ + public function load($uid) + { + $store = $this->psl['store']; + $storeData = $store->read('authy', $this->getStoreId($uid)); + + if($storeData !== false) { + $this->authyId = $storeData['authyId']; + return $this->authyId; + } + return false; + } + + private function getStoreId($uid) { + return hash('sha512', $uid); + } } diff --git a/lib/phpSec/Auth/Gridcard.php b/lib/phpSec/Auth/Gridcard.php new file mode 100644 index 0000000..adf4bae --- /dev/null +++ b/lib/phpSec/Auth/Gridcard.php @@ -0,0 +1,273 @@ + + @copyright Copyright (c) Audun Larsen, 2011, 2012 + @link https://github.com/phpsec/phpSec + @license http://opensource.org/licenses/mit-license.php The MIT License + @package phpSec_Experimental + */ + +/** + * Providees pre shared password grid functionality. Experimental. + * @package phpSec_Experimental + */ +class Gridcard { + + public $numCols = 10; + public $numRows = 5; + public $gridChars = '0123456789'; + public $_charset = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + private $seedRandom; + private $nextCellsRandomSeed; + + /** + * Constructor. + * + * @param \phpSec\Core $psl + * phpSec core Pimple container. + */ + public function __construct(\phpSec\Core $psl) { + $this->psl = $psl; + } + + public function generate($expiry = null) { + $rand = $this->psl['crypt/rand']; + + $this->issued = time(); + + if (isset($expiry)) { + $this->expiry = $expiry; + } + else { + $this->expiry = strtotime("+ 1 year"); + } + + $this->seedRandom = $rand->str(64, $this->_charset); + + // Total number of different combinations is (numCols * numRows)^3 + $this->nextCellsRandomSeed = mt_rand(0, pow($this->numCols * $this->numRows, 3)); + } + + public function save($uid) + { + if (!isset($this->seedRandom) + || !isset($this->expiry) + || !isset($this->nextCellsRandomSeed) + ) { + throw new \phpSec\Exception\GeneralSecurityException('Variables not set correctly'); + } + $store['numCols'] = $this->numCols; + $store['numRows'] = $this->numRows; + $store['seedRandom'] = $this->seedRandom; + $store['chars'] = $this->gridChars; + $store['expiry'] = $this->expiry; + $store['nextCellsSeed'] = $this->nextCellsRandomSeed; + + $storeId = $this->getStoreId($uid); + + $this->psl['store']->write('gridcard', $storeId, $store); + } + + public function validate(Array $values, $uid) + { + $this->getGridValues(); + $cells = $this->getNextCells(); + + for ($i=0; $i < count($cells); $i++) { + preg_match('/\D+/', $cells[$i], $col_matches); + preg_match('/\d+/', $cells[$i], $row_matches); + $col = $col_matches[0]; + $row = $row_matches[0]; + + if (!$this->_validateCell($col, $row, $values[$i])) { + // Get new random seed for next cells + $this->_updateNextCellsRandomSeed($uid); + + return false; + } + } + // Get new random seed for next cells + $this->_updateNextCellsRandomSeed($uid); + return true; + } + + /** + * Validates the value from a specific cell + * @Param mixed $col Integer column number or string column name + * @Param Integer $row row number + * @Param String $val Value to check against. + * @Note This will show false negatives if $val is not a string for cell + * values that start with 0. + */ + private function _validateCell($col, $row, $val) + { + if (!is_numeric($col)) { + $col = $this->_letters_to_num($col); + } + $this->getGridValues(); + + return ((string)$this->_values[$row-1][$col-1] === (string)$val); + } + + public function load($uid) + { + $store = $this->psl['store']; + $storeData = $store->read('gridcard', $this->getStoreId($uid)); + + if($storeData !== false) { + // Delete the entry if it has expired + if ($storeData['expiry'] < time()) { + $store->delete('gridcard', $this->getStoreId($uid)); + return false; + } + + $this->numCols = $storeData['numCols']; + $this->numRows = $storeData['numRows']; + $this->seedRandom = $storeData['seedRandom']; + $this->gridChars = $storeData['chars']; + $this->expiry = $storeData['expiry']; + $this->nextCellsRandomSeed = $storeData['nextCellsSeed']; + + return true; + } + return false; + } + + /** + * Gets the next 3 cells to be used for validation. + * @Note Refreshing the page should *not* get different values. Only after + * validating should they change + */ + public function getNextCells() + { + $next_cells = array(); + // Seed the random number generator + mt_srand($this->nextCellsRandomSeed); + for ($i=0; $i < 3; $i++) { + // Loop to make sure next values are unique + while (!isset($next_cells[$i])) { + $value = $this->_num_to_letters(mt_rand(1, $this->numCols)); + $value .= mt_rand(1, $this->numRows); + if (array_search($value, $next_cells) === false) { + $next_cells[$i] = $value; + } + } + } + return $next_cells; + } + + public function getGridHTML() + { + $this->getGridValues(); + + $html = ' +
| '; + + for ($c=1; $c<=$this->numCols; $c++) { + $html .= ' | '.$this->_num_to_letters($c).' | '; + } + + $html .= ' +
| '.($r+1).' | '; + } + else { + $html .= ''.$this->_values[$r][$c-1].' | '; + } + } + $html .= '