1: <?php
2:
3: /**
4: * This file is part of the Nette Framework (https://nette.org)
5: * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6: */
7:
8: namespace Nette\Forms\Controls;
9:
10: use Nette;
11:
12:
13: /**
14: * CSRF protection field.
15: */
16: class CsrfProtection extends HiddenField
17: {
18: const PROTECTION = 'Nette\Forms\Controls\CsrfProtection::validateCsrf';
19:
20: /** @var Nette\Http\Session */
21: public $session;
22:
23:
24: /**
25: * @param string|object
26: */
27: public function __construct($errorMessage)
28: {
29: parent::__construct();
30: $this->setOmitted()
31: ->setRequired()
32: ->addRule(self::PROTECTION, $errorMessage);
33: $this->monitor(Nette\Application\UI\Presenter::class);
34: }
35:
36:
37: protected function attached($parent)
38: {
39: parent::attached($parent);
40: if (!$this->session && $parent instanceof Nette\Application\UI\Presenter) {
41: $this->session = $parent->getSession();
42: }
43: }
44:
45:
46: /**
47: * @return static
48: * @internal
49: */
50: public function setValue($value)
51: {
52: return $this;
53: }
54:
55:
56: /**
57: * Loads HTTP data.
58: * @return void
59: */
60: public function loadHttpData()
61: {
62: $this->value = $this->getHttpData(Nette\Forms\Form::DATA_TEXT);
63: }
64:
65:
66: /**
67: * @return string
68: */
69: public function getToken()
70: {
71: $session = $this->getSession()->getSection(__CLASS__);
72: if (!isset($session->token)) {
73: $session->token = Nette\Utils\Random::generate();
74: }
75: return $session->token ^ $this->getSession()->getId();
76: }
77:
78:
79: /**
80: * @return string
81: */
82: private function generateToken($random = null)
83: {
84: if ($random === null) {
85: $random = Nette\Utils\Random::generate(10);
86: }
87: return $random . base64_encode(sha1($this->getToken() . $random, true));
88: }
89:
90:
91: /**
92: * Generates control's HTML element.
93: * @return Nette\Utils\Html
94: */
95: public function getControl()
96: {
97: return parent::getControl()->value($this->generateToken());
98: }
99:
100:
101: /**
102: * @return bool
103: * @internal
104: */
105: public static function validateCsrf(self $control)
106: {
107: $value = (string) $control->getValue();
108: return $control->generateToken(substr($value, 0, 10)) === $value;
109: }
110:
111:
112: /********************* backend ****************d*g**/
113:
114:
115: /**
116: * @return Nette\Http\Session
117: */
118: private function getSession()
119: {
120: if (!$this->session) {
121: $this->session = new Nette\Http\Session($this->getForm()->httpRequest, new Nette\Http\Response);
122: }
123: return $this->session;
124: }
125: }
126: