<?php
/* 
 * Cross-site Request Forgery Synchronizer Tokens
 * A simple class for generating CSRF tokens in the Synchronizer Token Pattern.
 * For more information, @see http://halls-of-valhalla.org/beta/articles/cross-site-request-forgery-demystified,47/
 * 
 * @author ynori7
 * @copyright Copyright (c) 2014, halls-of-valhalla.org
 * @license http://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0 International License. 
 * 
 * Example Usage:
 * $csrfToken = new CsrfToken();
 * if($csrfToken->isValidToken($_POST)){
 *   //CSRF token is valid, so perform action
 * }
 * 
 * To display in forms, just use:
 * $token = $csrfToken->getToken();
 */

namespace Valhalla\CoreUtilities\Security;

use Valhalla\CoreUtilities\Http\HttpSession;

class CsrfToken {
    const TOKEN_NAME = 'CSRFToken';
    
    /**
     * @var Valhalla\CoreUtilities\Http\SessionInterface
     */
    protected $_session;
    
    /**
     * Gets a token from the session. If there isn't one, puts one there.
     * 
     * @return string
     */
    public function getToken() {
        $session = $this->getSession();
        if ($session->get(self::TOKEN_NAME) === false){
            $session->set(self::TOKEN_NAME, self::generateToken());
        }
        return $session->get(self::TOKEN_NAME);
    }
    
    /**
     * Checks if the CSRF token is set in the request.
     * 
     * @param array $requestParams
     * @return boolean
     */
    public function isTokenSet($requestParams){
        return ( !empty($requestParams[self::TOKEN_NAME]) );
    }

    /**
     * Checks if there exists a token and if it's valid.
     * 
     * @param array $requestParams
     * @return boolean
     */
    public function isValidToken($requestParams) {
        return ($this->isTokenSet($requestParams) and
                self::getToken() === $requestParams[self::TOKEN_NAME]);
    }

    /**
     * Generates a unique token.
     * 
     * @return string
     */
    protected function generateToken() {
        return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
                mt_rand(0, 0xffff), 
                mt_rand(0, 0xffff), 
                mt_rand(0, 0xffff), 
                mt_rand(0, 0x0fff) | 0x4000, 
                mt_rand(0, 0x3fff) | 0x8000, 
                mt_rand(0, 0xffff), 
                mt_rand(0, 0xffff), 
                mt_rand(0, 0xffff)
        );
    }
    
    /**
     * Sets the session variable to be used. 
     * 
     * @param Valhalla\CoreUtilities\Http\SessionInterface $session
     */
    public function setSession($session){
        $this->_session = $session;
    }
    
    /**
     * Gets the session object if set, otherwise uses HttpSession by default.
     * 
     * @return Valhalla\CoreUtilities\Http\SessionInterface
     */
    public function getSession(){
        if(is_null($this->_session)){
            $this->setSession(new HttpSession());
        }
        return $this->_session;
    }

}