diff --git a/.gitignore b/.gitignore index 945a9fe..770a718 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ incoming_symbols logs htdocs/lib/logs htdocs/lib/irc_passwd +htdocs/lib/init.php .hg* *.7z diff --git a/htdocs/lib/GoogleLogin.php b/htdocs/lib/GoogleLogin.php new file mode 100644 index 0000000..ed97584 --- /dev/null +++ b/htdocs/lib/GoogleLogin.php @@ -0,0 +1,103 @@ + +* @copyright Copyright © 2012-2014, Latif Khalifa +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files +* (the "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit +* persons to whom the Software is furnished to do so, subject to the +* following conditions: +* +* - The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*/ + + +class GoogleLogin +{ + static $client = null; + static $clientID; + static $clientSecret; + static $scope = "openid email"; + static $accessToken; + + static function init($clientID, $clientSecret) + { + self::$clientID = $clientID; + self::$clientSecret = $clientSecret; + } + + static function getClient() + { + if (self::$client == null) + { + $client = new Google_Client(); + $client->setClientId(self::$clientID); + $client->setClientSecret(self::$clientSecret); + $client->setRedirectUri(URL_ROOT . "/process_login.php" ); + $client->setScopes("email"); + self::$client = $client; + } + + return self::$client; + } + + static function loginURL() + { + $client = self::getClient(); + return $client->createAuthUrl(); + } + + static function verifyLogin($code) + { + try + { + $client = self::getClient(); + $client->authenticate($code); + self::$accessToken = $client->getAccessToken(); + return true; + } + catch (Exception $e) + { + return false; + } + } + + static function getAttribs() + { + $client = self::getClient(); + $attr = $client->verifyIdToken()->getAttributes(); + return $attr["payload"]; + } + + static function userID() + { + $attr = self::getAttribs(); + return $attr["sub"]; + } + + static function userEmail() + { + $attr = self::getAttribs(); + return $attr["email"]; + } + + +} \ No newline at end of file diff --git a/htdocs/lib/GoogleOpenID.php b/htdocs/lib/GoogleOpenID.php deleted file mode 100644 index abe5e1e..0000000 --- a/htdocs/lib/GoogleOpenID.php +++ /dev/null @@ -1,478 +0,0 @@ -redirect(); - * - * OR - * - * $handle = GoogleOpenID::getAssociationHandle(); // <--save this! valid for two weeks! - * - * $googleGateway = GoogleOpenID::createRequest("http://www.mydomain.com/checkauth.php", $handle, true); - * $googleGateway->redirect(); - * - * - * When you want to recieve a Google OpenID response, simply pass the given - * parameters to GoogleOpenID::create(). In most cases, you should just be able - * to pass the $_GET variable. - * - * To continue the previous example, the following code would go in checkauth.php - * - * $googleResponse = GoogleOpenID::create($_GET); - * $sucess = $googleResponse->success();//true or false - * $user_identity = $googleResponse->identity();//the user's ID - * $user_email = $googleResponse->email();//the user's email - * - * OR, even easier - * - * $googleResponse = GoogleOpenID::getResponse(); // <-- automatically reads $_GET - * - * Advanced users can create a slightly more customized request using the create - * method. It accepts an associative array of openid parameters and sets those - * that it deems appropriate to set (mostly, the parameters that don't have a - * definite value when interacting with Google) - * - * - * Full class signature: - * - * public static createRequest(String, [String], [Boolean]) - * public static getResponse() - * public static create(Array) - * public static getAssociationHandle([String]) - * public static getEndPoint() - * public redirect() - * public getArray() - * public endPoint() - * public success() - * public assoc_handle() - * public email() - * public identity() - * - * Features to implement: - * - * -In constructor, fix relative->absolute URL conversion (it is messy/buggy) - * -In getAssociationHandle(), use encryption - * -Verify Google's response with signed, sig etc - ****************************************************************************/ - - class GoogleOpenID{ - //the google discover url - const google_discover_url = "https://www.google.com/accounts/o8/id"; - - //some constant parameters - const openid_ns = "http://specs.openid.net/auth/2.0"; - //required for email attribute exchange - const openid_ns_ext1 = "http://openid.net/srv/ax/1.0"; - const openid_ext1_mode = "fetch_request"; - const openid_ext1_type_email = "http://schema.openid.net/contact/email"; - const openid_ext1_required = "email"; - - //parameters set by constructor - private $mode;//the mode (checkid_setup, id_res, or cancel) - private $response_nonce; - private $return_to;//return URL - private $realm;//the realm that the user is being asked to trust - private $assoc_handle;//the association handle between this service and Google - private $claimed_id;//the id claimed by the user - private $identity;//for google, this is the same as claimed_id - private $signed; - private $sig; - private $email;//the user's email address - - //if true, fetch email address - private $require_email; - - //private constructor - private function GoogleOpenID($mode, $op_endpoint, $response_nonce, $return_to, $realm, $assoc_handle, $claimed_id, $signed, $sig, $email, $require_email){ - - //if assoc_handle is null, fetch one - if(is_null($assoc_handle)) - $assoc_handle = GoogleOpenID::getAssociationHandle(); - - //if return_to is a relative URL, make it absolute - if(stripos($return_to, "http://")!==0 && - stripos($return_to, "https://")!==0){ - //if the first character is a slash, delete it - if(substr($return_to, 0, 1)=="/") - $return_to = substr($return_to, 1); - //get the position of server_name - $server_name_pos = stripos($return_to, $_SERVER['SERVER_NAME']); - //if server_name is already at position zero - if($server_name_pos != false && $server_name_pos==0){ - $return_to = "http://".$return_to; - } else { - $return_to = "http://".$_SERVER['SERVER_NAME']."/".$return_to; - }//else (server name not at position zero) - }//if return_to is relative - - //if realm is null, attempt to set it via return_to - if(is_null($realm)){ - //if return_to is set - if(!is_null($return_to)){ - $pieces = parse_url($return_to); - $realm = $pieces['scheme']."://".$pieces['host']; - }//if return_to set - }//if realm null - - $this->mode = $mode; - $this->op_endpoint = $op_endpoint; - $this->response_nonce = $response_nonce; - $this->return_to = $return_to; - $this->realm = $realm; - $this->assoc_handle = $assoc_handle; - $this->claimed_id = $claimed_id; - $this->identity = $claimed_id; - $this->signed = $signed; - $this->sig = $sig; - $this->email = $email; - $this->require_email = ($require_email) ? true : false; - }//GoogleOpenID - - //static creator that accepts only a return_to URL - //this creator should be used when creating a GoogleOpenID for a redirect - public static function createRequest($return_to, $assoc_handle=null, $require_email=false){ - return new GoogleOpenID("checkid_setup", null, null, $return_to, null, $assoc_handle, "http://specs.openid.net/auth/2.0/identifier_select", null, null, null, $require_email); - }//createRequest - - //static creator that accepts an associative array of parameters and - //sets only the setable attributes (does not overwrite constants) - public static function create($params){ - //loop through each parameter - foreach($params as $param => $value){ - switch($param){ - case "openid_mode": - //check validity of mode - if($value=="checkid_setup" || - $value=="id_res" || - $value=="cancel") - $mode = $value; - else - $mode = "cancel"; - continue 2; - - case "openid_op_endpoint": - $op_endpoint = $value; - continue 2; - - case "openid_response_nonce": - $response_nonce = $value; - continue 2; - - case "openid_return_to": - $return_to = $value; - continue 2; - - case "openid_realm": - $realm = $value; - continue 2; - - case "openid_assoc_handle": - $assoc_handle = $value; - continue 2; - - case "openid_claimed_id": - $claimed_id = $value; - continue 2; - - case "openid_identity": - $claimed_id = $value; - continue 2; - - case "openid_signed": - $signed = $value; - continue 2; - - case "openid_sig": - $sig = $value; - continue 2; - - case "openid_ext1_value_email": - $email = $value; - continue 2; - - case "require_email": - $require_email = $value; - continue 2; - - default: - continue 2; - }//switch param - }//loop through params - - //if require email is not set, set it to false - if(!is_bool($require_email)) - $require_email = false; - //if mode is not set, set to default for redirection - if(is_null($mode)) - $mode = "checkid_setup"; - //if return_to is not set and mode is checkid_setup, throw an error - if(is_null($return_to) && $mode=="checkid_setup") - throw new Exception("GoogleOpenID.create() needs parameter openid.return_to"); - - //return a new GoogleOpenID with the given parameters - return new GoogleOpenID($mode, $op_endpoint, $response_nonce, $return_to, $realm, $assoc_handle, $claimed_id, $signed, $sig, $email, $require_email); - }//create - - //creates and returns a GoogleOpenID from the $_GET variable - public static function getResponse(){ - return GoogleOpenID::create($_GET); - }//getResponse - - //fetches an association handle from google. association handles are valid - //for two weeks, so coders should do their best to save association handles - //externally and pass them to createRequest() - //NOTE: This function does not use encryption, but it SHOULD! At the time - //I wrote this I wanted it done fast, and I couldn't seem to find a good - //two-way SHA-1 or SHA-256 library for PHP. Encryption is not my thing, so - //it remains unimplemented. - public static function getAssociationHandle($endpoint=null){ - //if no endpoint given - if(is_null($endpoint)) - //fetch one from Google - $request_url = GoogleOpenID::getEndPoint(); - //if endpoint given, set it - else - $request_url = $endpoint; - - //append parameters (these never change) - $request_url .= "?openid.ns=".urlencode(GoogleOpenID::openid_ns); - $request_url .= "&openid.mode=associate"; - $request_url .= "&openid.assoc_type=HMAC-SHA1"; - $request_url .= "&openid.session_type=no-encryption"; - - //create a CURL session with the request URL - $c = curl_init($request_url); - - //set a few options - curl_setopt($c, CURLOPT_RETURNTRANSFER, true); - curl_setopt($c, CURLOPT_HEADER, false); - - //get the contents of request URL - $request_contents = curl_exec($c); - - //close the CURL session - curl_close($c); - - //a handle to be returned - $assoc_handle = null; - - //split the response into lines - $lines = explode("\n", $request_contents); - - //loop through each line - foreach($lines as $line){ - //if this line is assoc_handle - if(substr($line, 0, 13)=="assoc_handle:"){ - //save the assoc handle - $assoc_handle = substr($line, 13); - //exit the loop - break; - }//if this line is assoc_handle - }//loop through lines - - //return the handle - return $assoc_handle; - }//getAssociationHandle - - //fetches an endpoint from Google - public static function getEndPoint(){ - //fetch the request URL - $request_url = GoogleOpenID::google_discover_url; - - //create a CURL session with the request URL - $c = curl_init($request_url); - - //set a few options - curl_setopt($c, CURLOPT_RETURNTRANSFER, true); - curl_setopt($c, CURLOPT_HEADER, false); - - //fetch the contents of the request URL - $request_contents = curl_exec($c); - - //close the CURL session - curl_close($c); - - //create a DOM document so we can extract the URI element - $domdoc = new DOMDocument(); - $domdoc->loadXML($request_contents); - - //fetch the contents of the URI element - $uri = $domdoc->getElementsByTagName("URI"); - $uri = $uri->item(0)->nodeValue; - - //return the given URI - return $uri; - }//getEndPoint - - //returns an associative array of all openid parameters for this openid - //session. the array contains all the GET attributes that would be sent - //or that have been recieved, meaning: - // - //if mode = "cancel" returns only the mode and ns attributes - //if mode = "id_res" returns all attributes that are not null - //if mode = "checkid_setup" returns only attributes that need to be sent - // in the HTTP request - public function getArray(){ - //an associative array to return - $ret = array(); - - $ret['openid.ns'] = GoogleOpenID::openid_ns; - - //if mode is cancel, return only ns and mode - if($this->mode=="cancel"){ - $ret['openid.mode'] = "cancel"; - return $ret; - }//if cancel - - //set attributes that are returned for all cases - if(!is_null($this->claimed_id)){ - $ret['openid.claimed_id'] = $this->claimed_id; - $ret['openid.identity'] = $this->claimed_id; - } - if(!is_null($this->return_to)) - $ret['openid.return_to'] = $this->return_to; - if(!is_null($this->realm)) - $ret['openid.realm'] = $this->realm; - if(!is_null($this->assoc_handle)) - $ret['openid.assoc_handle'] = $this->assoc_handle; - if(!is_null($this->mode)) - $ret['openid.mode'] = $this->mode; - - //set attributes that are returned only if this is a request - //and if getting email is required OR if this is a response and the - //email is given - if(($this->mode=="checkid_setup" AND $this->require_email) OR - ($this->mode=="id_res" AND !is_null($this->email))){ - $ret['openid.ns.ext1'] = GoogleOpenID::openid_ns_ext1; - $ret['openid.ext1.mode'] = GoogleOpenID::openid_ext1_mode; - $ret['openid.ext1.type.email'] = GoogleOpenID::openid_ext1_type_email; - $ret['openid.ext1.required'] = GoogleOpenID::openid_ext1_required; - if(!is_null($this->email)) - $ret['openid.ext1.value.email'] = $this->email; - }//if redirect and get email - - //set attributes that are returned only if this is a response - if($this->mode=="id_res"){ - $ret['openid.op_endpoint'] = $this->op_endpoint; - if(!is_null($this->response_nonce)) - $ret['openid.response_nonce'] = $this->response_nonce; - if(!is_null($this->signed)) - $ret['openid.signed'] = $this->signed; - if(!is_null($this->sig)) - $ret['openid.sig'] = $this->sig; - } - - //return the array - return $ret; - }//getArray - - //sends a request to google and fetches the url to which google is asking - //us to redirect (unless the endpoint is already known, in which case the - //function simply returns it) - public function endPoint(){ - //if we know the value of op_endpoint already - if(!is_null($this->op_endpoint)) - return $this->op_endpoint; - - //fetch the endpoint from Google - $endpoint = GoogleOpenID::getEndPoint(); - - //save it - $this->op_endpoint = $endpoint; - - //return the endpoint - return $endpoint; - }//getedPoint - - //returns the URL to which we should send a request (including all GET params) - public function getRequestURL(){ - //get all parameters - $params = $this->getArray(); - - //the base URL - $url = $this->endPoint(); - - //flag indicating whether to set a '?' or an '&' - $first_attribute = true; - - //loop through all params - foreach($params as $param => $value){ - //if first attribute print a ?, else print a & - if($first_attribute){ - $url .= "?"; - $first_attribute = false; - } else { - $url .= "&"; - }//else (not first attribute) - - $url .= urlencode($param) . "=" . urlencode($value); - }//loop through params - - //return the URL - return $url; - }//getRequestURL - - //redirects the browser to the appropriate request URL - public function redirect(){ - header("Location: ".$this->getRequestURL()); - }//redirect - - //returns true if the response was a success - public function success(){ - return ($this->mode=="id_res"); - }//success - - //returns the identity given in the response - public function identity(){ - if($this->mode!="id_res") - return null; - else - return $this->claimed_id; - }//identity - - //returns the email given in the response - public function email(){ - if($this->mode!="id_res") - return null; - else - return $this->email; - }//email - - //returns the assoc_handle - public function assoc_handle(){ - return $this->assoc_handle(); - }//assoc_handle - }//class GoogleOpenID -?> diff --git a/htdocs/lib/Layout.php b/htdocs/lib/Layout.php index 0ca8ee4..e576e1b 100644 --- a/htdocs/lib/Layout.php +++ b/htdocs/lib/Layout.php @@ -32,27 +32,6 @@ class Layout { - static function getLoginGateway() - { - $assoc_handle_expires = (int)Option::get('assoc_handle_expires'); - $now = time(); - - $assoc_handle = Option::get("assoc_handle"); - - if (!$assoc_handle || $assoc_handle_expires < $now) - { - $assoc_handle_expires = time() + 604800; - $assoc_handle = GoogleOpenID::getAssociationHandle(); - if ($assoc_handle) - { - Option::update("assoc_handle_expires", $assoc_handle_expires); - Option::update("assoc_handle", $assoc_handle); - } - } - - return GoogleOpenID::createRequest(URL_ROOT . "/process_login.php", $handle, true); - } - static function since($since) { $since = time() - $since; @@ -88,7 +67,7 @@ class Layout { $item = new stdClass; $item->label = "Login"; - $item->link = self::getLoginGateway()->getRequestURL(); + $item->link = GoogleLogin::loginURL(); $menu[] = $item; } else diff --git a/htdocs/lib/init.php b/htdocs/lib/init.php.in similarity index 79% rename from htdocs/lib/init.php rename to htdocs/lib/init.php.in index c8e5fe1..d08a431 100644 --- a/htdocs/lib/init.php +++ b/htdocs/lib/init.php.in @@ -59,9 +59,9 @@ if (!defined('IMG_ROOT')) { $DB = DBH::getInstance(); -$DB_NAME = "singucrash"; -$DB_USER = 'singucrash'; -$DB_PASS = '-*-secrit-*-'; +$DB_NAME = 'replex_crash'; +$DB_USER = 'replex_crash'; +$DB_PASS = 'replex_sekrit'; $DB_HOST = 'localhost'; if (!DBH::$db->connect($DB_NAME, $DB_HOST, $DB_USER, $DB_PASS)) { @@ -69,8 +69,17 @@ if (!DBH::$db->connect($DB_NAME, $DB_HOST, $DB_USER, $DB_PASS)) { die(); } +// Google API settings +set_include_path(get_include_path() . PATH_SEPARATOR . SITE_ROOT . '/lib'); +require_once 'Google/Client.php'; +$GoogleClientID = "get client id at google dev console"; +$GoogleClientSecret = "secret from google dev console"; +GoogleLogin::init($GoogleClientID, $GoogleClientSecret); + +// Options Option::init(); +// Session if (!defined('NO_SESSION') && PHP_SAPI != "cli") { $S = new Session(); $S->check(); diff --git a/htdocs/process_login.php b/htdocs/process_login.php index 94f169c..78e2c91 100644 --- a/htdocs/process_login.php +++ b/htdocs/process_login.php @@ -3,15 +3,14 @@ define("SITE_ROOT", realpath(dirname(__file__))); require_once SITE_ROOT . "/lib/init.php"; -$google_response = GoogleOpenID::getResponse(); -$success = $google_response->success();//true or false -if (!$success) + +if (!isset($_GET["code"]) || !GoogleLogin::verifyLogin($_GET["code"])) { http::redirect("/login_failed.php"); } -$user_identity = $google_response->identity();//the user's ID -$user_email = $google_response->email();//the user's email +$user_identity = GoogleLogin::userID(); +$user_email = GoogleLogin::userEmail(); $user = User::getByLogin($user_identity);