Skip to content

Instantly share code, notes, and snippets.

@JanTvrdik
Forked from hrach/BasePresenter.php
Created January 2, 2012 10:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JanTvrdik/1550180 to your computer and use it in GitHub Desktop.
Save JanTvrdik/1550180 to your computer and use it in GitHub Desktop.
Secured signlas - old NETTE!
<?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);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment