Skip to content

Instantly share code, notes, and snippets.

@hrach
Created December 31, 2011 20:12

Revisions

  1. hrach created this gist Dec 31, 2011.
    216 changes: 216 additions & 0 deletions BasePresenter.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,216 @@
    <?php
    /**
    * Signály.cz – JP2
    * ----------------
    *
    * @license MIT License http://en.wikipedia.org/wiki/MIT_License
    * @link http://signaly.cz
    */

    use Nette;
    use Nette\Debug;
    use Nette\Logger;
    use Nette\Logger\ILogger;
    use Nette\Environment as Env;
    use Nette\Application\AppForm;
    use Nette\Application\BadRequestException;
    use Nette\Application\ForbiddenRequestException;
    use Nette\Application\Presenter;
    use Nette\Security\AuthenticationException;
    use DateTime;


    abstract class BasePresenter extends Presenter
    {


    /**
    * Zkontroluje zda má uživatel potřebné oznámení oprávnení a pokud ne, podnikne patřičné kroky
    *
    * @author Jan Tvrdík
    * @param string|IRowResource
    * @param string
    * @return void
    * @throws ForbiddenRequestException
    */
    public function requirePrivilege($resource, $action = NULL)
    {
    if (!$this->actor->isAllowed($resource, $action)) {
    $this->requireLogin();
    throw new ForbiddenRequestException('Nemáš tady co dělat!');
    }
    }

    /**
    * Vynutí přihlášenost uživatele.
    *
    * @author Jan Tvrdík
    * @return void
    */
    public function requireLogin()
    {
    if (!$this->actor->isLoggedIn()) {
    $storedRequest = $this->getApplication()->storeRequest();
    $this->redirect(':Auth:requireLogin', array('backlink' => $storedRequest));
    }
    }

    /**
    * Zpracuje anotace u dané metody
    *
    * Podporované anotace:
    * - @privilege(resource, action)
    * - @requireLogin
    * - @allowedAction(edit)
    * - @secured
    * - @onlyAjax
    *
    * @author Jan Tvrdík
    * @param string název metody
    * @return void
    */
    private function processMethodAnnotations($method)
    {
    if (!method_exists($this, $method)) return; // přeskočí zpracování, pokud metoda neexistuje

    $reflection = $this->getReflection()->getMethod($method);
    $annotations = $reflection->getAnnotations();

    if (isset($annotations['privilege'])) {
    foreach ($annotations['privilege'] as $privilige) {
    $this->requirePrivilege($privilige[0], $privilige[1]);
    }
    }

    if (isset($annotations['requireLogin'])) {
    $this->requireLogin();
    }

    if (isset($annotations['allowedAction'])) {
    $allowedActions = $annotations['allowedAction'];
    if (!in_array($this->action, $allowedActions)) {
    throw new ForbiddenRequestException('Volání metody ' . $method . ' není pro akci ' . $this->action . ' povoleno. Zkontrolujte anotaci @allowedAction.');
    }
    }

    if (isset($annotations['secured'])) {
    $protectedParams = array();
    foreach ($reflection->getParameters() as $param) {
    if ($param->isOptional()) continue;
    $protectedParams[$param->name] = $this->getParam($param->name);
    }
    if ($this->getParam('__secu') !== $this->createSecureHash($protectedParams)) {
    throw new ForbiddenRequestException('Secured parameters are not valid.');
    }
    }

    if (isset($annotations['onlyAjax'])) {
    if (!$this->isAjax()) {
    throw new ForbiddenRequestException("Metoda $method přijímá pouze AJAXové požadavky. Viz anotace @onlyAjax");
    }
    }
    }


    // === Zabezpečení signalů =====================================================

    /**
    * Zajistí vyhodnocení anotací nad handlerem signálu.
    *
    * @author Jan Skrasek, Jan Tvrdík
    * @param string název signálu
    * @return void
    * @throws BadSignalException
    */
    public function signalReceived($signal)
    {
    $this->processMethodAnnotations($this->formatSignalMethod($signal));
    parent::signalReceived($signal);
    }

    /**
    * Generates link. If links points to @secure annotated signal handler method, additonal
    * parameter preventing changing parameters will be added.
    *
    * @author Jan Skrasek
    * @param string $destination
    * @param array|mixed $args
    * @return string
    */
    public function link($destination, $args = array())
    {
    if (!is_array($args)) {
    $args = func_get_args();
    array_shift($args);
    }

    $link = parent::link($destination, $args);
    $lastRequest = $this->presenter->lastCreatedRequest;

    // spatny link
    if ($lastRequest === NULL) return $link;

    // neni signal
    if (substr($destination, - 1) !== '!') return $link;

    // jen na stejny presenter
    if ($this->getPresenter()->getName() !== $lastRequest->getPresenterName()) return $link;

    $destination = str_replace(':', '-', $destination);
    if (strpos($destination, '-') !== FALSE) {
    $pos = strrpos($destination, '-');
    $signal = substr($destination, $pos + 1, -1);
    $component = substr($destination, 0, $pos);
    $component = $this->getComponent($component);
    } else {
    $signal = substr($destination, 0, -1);
    $component = $this;
    }

    // jen komponenty
    if (!$component instanceof Nette\Application\PresenterComponent) return $link;

    $method = $component->formatSignalMethod($signal);
    $reflection = Nette\Reflection\MethodReflection::from($component, $method);

    // nema anotaci
    if (!$reflection->hasAnnotation('secured')) return $link;

    $origParams = $lastRequest->getParams();
    $protectedParams = array();
    foreach ($reflection->getParameters() as $key => $param) {
    if ($param->isOptional()) continue;
    $protectedParams[$param->name] = $origParams[$component->getParamId($param->name)];
    }

    $uniqueId = $this->getUniqueId();
    if (empty($uniqueId)) {
    $paramName = $component->getParamId('__secu');
    } else {
    $paramName = substr($component->getParamId('__secu'), strlen($uniqueId) + 1);
    }

    $args[$paramName] = $this->createSecureHash($protectedParams);

    return parent::link($destination, $args);
    }


    /**
    * Creates secure hash from array of arguments.
    *
    * @author Jan Skrasek
    * @param array $param
    * @return string
    */
    protected function createSecureHash($params)
    {
    $ns = $this->getSession('securedlinks');
    if ($ns->key === NULL) {
    $ns->key = uniqid();
    }
    $s = implode('|', array_keys($params)) . '|' . implode('|', array_values($params)) . $ns->key;
    return substr(md5($s), 4, 8);
    }

    }