Skip to content

Commit a3c0862

Browse files
committed
WIP
1 parent 4494892 commit a3c0862

File tree

2 files changed

+241
-0
lines changed

2 files changed

+241
-0
lines changed

src/SecuredRouter.php

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?php
2+
3+
4+
namespace Nextras\Application\UI;
5+
6+
use Nette;
7+
use Nette\Application\IPresenterFactory;
8+
use Nette\Application\IRouter;
9+
use Nette\Application\Request;
10+
use Nette\Application\UI\Presenter;
11+
use Nette\Http\Session;
12+
use ReflectionMethod;
13+
14+
15+
class SecuredRouter implements IRouter
16+
{
17+
/** @var IRouter */
18+
private $inner;
19+
20+
/** @var IPresenterFactory */
21+
private $presenterFactory;
22+
23+
/** @var Session */
24+
private $session;
25+
26+
27+
/**
28+
* @param IRouter $inner
29+
* @param IPresenterFactory $presenterFactory
30+
* @param Session $session
31+
*/
32+
public function __construct(IRouter $inner, IPresenterFactory $presenterFactory, Session $session)
33+
{
34+
$this->inner = $inner;
35+
$this->presenterFactory = $presenterFactory;
36+
$this->session = $session;
37+
}
38+
39+
40+
/**
41+
* @inheritdoc
42+
*/
43+
public function match(Nette\Http\IRequest $httpRequest)
44+
{
45+
$appRequest = $this->inner->match($httpRequest);
46+
47+
if ($appRequest !== NULL && $this->isSignatureRequired($appRequest) && !$this->isSignatureValid($appRequest)) {
48+
return NULL;
49+
}
50+
51+
return $appRequest;
52+
}
53+
54+
55+
/**
56+
* @inheritdoc
57+
*/
58+
public function constructUrl(Request $appRequest, Nette\Http\Url $refUrl)
59+
{
60+
if ($this->isSignatureRequired($appRequest)) {
61+
$signature = $this->getSignature($appRequest);
62+
$appRequest->setParameters(['_sec' => $signature] + $appRequest->getParameters());
63+
}
64+
65+
return $this->inner->constructUrl($appRequest, $refUrl);
66+
}
67+
68+
69+
/**
70+
* @param Request $appRequest
71+
* @return bool
72+
*/
73+
protected function isSignatureRequired(Request $appRequest)
74+
{
75+
$presenterName = $appRequest->getPresenterName();
76+
$presenterClass = $this->presenterFactory->getPresenterClass($presenterName);
77+
78+
if (!is_a($presenterClass, Presenter::class)) {
79+
return FALSE;
80+
}
81+
82+
$params = $appRequest->getParameters();
83+
84+
if (isset($params['action'])) {
85+
$methodName = $presenterClass::formatActionMethod($params['action']);
86+
$methodRef = new ReflectionMethod($presenterClass, $methodName);
87+
if ($this->isSecured($methodRef)) {
88+
return TRUE;
89+
}
90+
}
91+
92+
if (isset($params['do'])) {
93+
$methodName = $presenterClass::formatSignalMethod($params['do']);
94+
$methodRef = new ReflectionMethod($presenterClass, $methodName);
95+
if ($this->isSecured($methodRef)) {
96+
return TRUE;
97+
}
98+
}
99+
100+
return FALSE;
101+
}
102+
103+
104+
/**
105+
* @param ReflectionMethod $ref
106+
* @return bool
107+
*/
108+
public function isSecured(ReflectionMethod $ref)
109+
{
110+
return (bool) preg_match('#^[ \t*]*@secured(\s|$)#m', $ref->getDocComment());
111+
}
112+
113+
114+
/**
115+
* @param Request $appRequest
116+
* @return bool
117+
*/
118+
private function isSignatureValid(Request $appRequest)
119+
{
120+
$signature = $appRequest->getParameter('_sec');
121+
return ($signature !== NULL && hash_equals($this->getSignature($appRequest), $signature));
122+
}
123+
124+
125+
/**
126+
* @param Request $appRequest
127+
* @return string
128+
*/
129+
private function getSignature(Request $appRequest)
130+
{
131+
$sessionSection = $this->session->getSection('Nextras.Application.UI.SecuredLinksPresenterTrait');
132+
if (!isset($sessionSection->token)) {
133+
$sessionSection->token = function_exists('random_bytes')
134+
? random_bytes(16)
135+
: Nette\Utils\Random::generate(16, "\x00-\xFF");
136+
}
137+
138+
$data = [$this->session->getId(), $appRequest->getPresenterName(), $appRequest->getParameters()];
139+
$hash = hash_hmac('sha1', serialize($data), $sessionSection->token);
140+
return substr($hash, 0, 6);
141+
}
142+
}

src/SecuredRouterFlagBased.php

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
4+
namespace Nextras\Application\UI;
5+
6+
use Nette;
7+
use Nette\Application\IPresenterFactory;
8+
use Nette\Application\IRouter;
9+
use Nette\Application\Request;
10+
use Nette\Http\Session;
11+
12+
13+
class SecuredRouterFlagBased implements IRouter
14+
{
15+
16+
/** signed flag */
17+
const SIGNED = 'signed';
18+
19+
/** @var IRouter */
20+
private $inner;
21+
22+
/** @var IPresenterFactory */
23+
private $presenterFactory;
24+
25+
/** @var Session */
26+
private $session;
27+
28+
29+
/**
30+
* @param IRouter $inner
31+
* @param IPresenterFactory $presenterFactory
32+
* @param Session $session
33+
*/
34+
public function __construct(IRouter $inner, IPresenterFactory $presenterFactory, Session $session)
35+
{
36+
$this->inner = $inner;
37+
$this->presenterFactory = $presenterFactory;
38+
$this->session = $session;
39+
}
40+
41+
42+
/**
43+
* @inheritdoc
44+
*/
45+
public function match(Nette\Http\IRequest $httpRequest)
46+
{
47+
$appRequest = $this->inner->match($httpRequest);
48+
49+
if ($appRequest !== NULL && $this->isSignatureValid($appRequest)) {
50+
$appRequest->setFlag(self::SIGNED);
51+
}
52+
53+
return $appRequest;
54+
}
55+
56+
57+
/**
58+
* @inheritdoc
59+
*/
60+
public function constructUrl(Request $appRequest, Nette\Http\Url $refUrl)
61+
{
62+
if ($appRequest->hasFlag(self::SIGNED)) {
63+
$signature = $this->getSignature($appRequest);
64+
$appRequest->setParameters(['_sec' => $signature] + $appRequest->getParameters());
65+
}
66+
67+
return $this->inner->constructUrl($appRequest, $refUrl);
68+
}
69+
70+
71+
/**
72+
* @param Request $appRequest
73+
* @return bool
74+
*/
75+
private function isSignatureValid(Request $appRequest)
76+
{
77+
$signature = $appRequest->getParameter('_sec');
78+
return ($signature !== NULL && hash_equals($this->getSignature($appRequest), $signature));
79+
}
80+
81+
82+
/**
83+
* @param Request $appRequest
84+
* @return string
85+
*/
86+
private function getSignature(Request $appRequest)
87+
{
88+
$sessionSection = $this->session->getSection('Nextras.Application.UI.SecuredLinksPresenterTrait');
89+
if (!isset($sessionSection->token)) {
90+
$sessionSection->token = function_exists('random_bytes')
91+
? random_bytes(16)
92+
: Nette\Utils\Random::generate(16, "\x00-\xFF");
93+
}
94+
95+
$data = [$this->session->getId(), $appRequest->getPresenterName(), $appRequest->getParameters()];
96+
$hash = hash_hmac('sha1', json_encode($data), $sessionSection->token);
97+
return substr($hash, 0, 6);
98+
}
99+
}

0 commit comments

Comments
 (0)