Migrate captcha image and audio generation to extbase
[TYPO3CMS/Extensions/sr_freecap.git] / Classes / View / ImageGenerator / ShowPng.php
1 <?php
2 namespace SJBR\SrFreecap\View\ImageGenerator;
3 /***************************************************************
4 * Copyright notice
5 *
6 * (c) 2005-2012 Stanislas Rolland <typo3(arobas)sjbr.ca>
7 * All rights reserved
8 *
9 * This script is part of the TYPO3 project. The TYPO3 project is
10 * free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
17 * A copy is found in the textfile GPL.txt and important notices to the license
18 * from the author is found in LICENSE.txt distributed with these scripts.
19 *
20 *
21 * This script is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * This copyright notice MUST APPEAR in all copies of the script!
27 ***************************************************************/
28 /**
29 * Integrates freeCap v1.4.1 into TYPO3 and generates the freeCap CAPTCHA image.
30 *
31 *
32 * @author Stanislas Rolland <typo3(arobas)sjbr.ca>
33 */
34 /************************************************************\
35 *
36 * freeCap v1.4.1 Copyright 2005 Howard Yeend
37 * www.puremango.co.uk
38 *
39 * This file is part of freeCap.
40 *
41 * freeCap is free software; you can redistribute it and/or modify
42 * it under the terms of the GNU General Public License as published by
43 * the Free Software Foundation; either version 2 of the License, or
44 * (at your option) any later version.
45 *
46 * freeCap is distributed in the hope that it will be useful,
47 * but WITHOUT ANY WARRANTY; without even the implied warranty of
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49 * GNU General Public License for more details.
50 *
51 * You should have received a copy of the GNU General Public License
52 * along with freeCap; if not, write to the Free Software
53 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
54 *
55 *
56 \************************************************************/
57 /**
58 * Renders a png image of the CAPTCHA
59 *
60 * @author Stanislas Rolland <typo3(arobas)sjbr.ca>
61 */
62 class ShowPng implements \TYPO3\CMS\Extbase\MVC\View\ViewInterface {
63
64 /**
65 * @var string Name of the extension this view helper belongs to
66 */
67 protected $extensionName = 'SrFreecap';
68
69 /**
70 * @var string Name of the plugin this view helper belongs to
71 */
72 protected $pluginName = 'ImageGenerator';
73
74 /**
75 * @var string Key of the extension this view helper belongs to
76 */
77 protected $extensionKey = 'sr_freecap';
78
79 /**
80 * @var \TYPO3\CMS\Core\Domain\Model\Word
81 */
82 protected $word;
83
84 /**
85 * @var array Configuration of this view
86 */
87 protected $settings;
88
89 /**
90 * Sets the current controller context
91 *
92 * @param \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext
93 * @return void
94 */
95 public function setControllerContext(\TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext) {
96 }
97
98 /**
99 * Add a variable to the view data collection.
100 * Can be chained, so $this->view->assign(..., ...)->assign(..., ...); is possible
101 *
102 * @param string $key Key of variable
103 * @param mixed $value Value of object
104 * @return SJBR\SrFreecap\View\ImageGenerator\ShowPng an instance of $this, to enable chaining
105 * @api
106 */
107 public function assign($key, $value) {
108 switch ($key) {
109 case 'word':
110 $this->word = $value;
111 break;
112 case 'settings':
113 $this->settings = $value;
114 break;
115 }
116 return $this;
117 }
118
119 /**
120 * Add multiple variables to the view data collection
121 *
122 * @param array $values array in the format array(key1 => value1, key2 => value2)
123 * @return SJBR\SrFreecap\View\ImageGenerator\ShowPng an instance of $this, to enable chaining
124 * @api
125 */
126 public function assignMultiple(array $values) {
127 return $this;
128 }
129
130 /**
131 * Tells if the view implementation can render the view for the given context.
132 *
133 * @param \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext
134 * @return boolean TRUE if the view has something useful to display, otherwise FALSE
135 * @api
136 */
137 public function canRender(\TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext) {
138 return TRUE;
139 }
140
141 /**
142 * Initializes this view.
143 *
144 * @return void
145 * @api
146 */
147 public function initializeView() {
148 }
149
150 /**
151 * Renders the captcha image
152 *
153 * @return string empty string (the image is sent here)
154 */
155 public function render () {
156
157 // Avoid Brute Force Attacks:
158 if (!$this->word->getAttempts()) {
159 $this->word->setAttempts(1);
160 } else {
161 $this->word->setAttempts($this->word->getAttempts() + 1);
162 // if more than ($this->settings['maxAttempts']) refreshes, block further refreshes
163 // can be negated by connecting with new session id
164 // could get round this by storing num attempts in database against IP
165 // could get round that by connecting with different IP (eg, using proxy servers)
166 // in short, there's little point trying to avoid brute forcing
167 // the best way to protect against BF attacks is to ensure the dictionary is not
168 // accessible via the web or use random string option
169 if ($this->word->getAttempts() > $this->settings['maxAttempts']) {
170 $this->word->setWordHash('');
171 $this->word->setWordCypher(array());
172 $this->word->setHashFunction('');
173 $wordRepository->setWord($this->word);
174 $string = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('max_attempts', $extensionName);
175 $font = 5;
176 $width = imagefontwidth($font) * strlen($string);
177 $height = imagefontheight($font);
178 $image = ImageCreate($width+2, $height+20);
179 $background = ImageColorAllocate($image, 255,255,255);
180 ImageColorTransparent($image, $background);
181 $red = ImageColorAllocate($image, 255, 0, 0);
182 ImageString($image, $font, 1, 10, $string, $red);
183 \SJBR\SrFreecap\Utility\ImageContentUtility::sendImage($image, $this->settings['imageFormat']);
184 ImageDestroy($image);
185 // Return an empty string
186 return '';
187 }
188 }
189
190 // Get random word
191 $word = \SJBR\SrFreecap\Utility\RandomContentUtility::getRandomWord($this->settings['useWordsList'], $this->settings['wordsListLocation'], $this->settings['generateNumbers'], $this->settings['maxWordLength']);
192
193 // Save hash of word for comparison
194 // using hash so that if there's an insecurity elsewhere (eg on the form processor),
195 // an attacker could only get the hash
196 // also, shared servers usually give all users access to the session files
197 // echo `ls /tmp`; and echo `more /tmp/someone_elses_session_file`; usually work
198 // so even if your site is 100% secure, someone else's site on your server might not be
199 // hence, even if attackers can read the session file, they can't get the freeCap word
200 // (though most hashes are easy to brute force for simple strings)
201 $this->word->setWordHash(md5($word));
202
203 // We use a simple encrypt to prevent the session from being exposed
204 if ($this->settings['accessibleOutput']) {
205 $this->word->setWordCypher(\SJBR\SrFreecap\Utility\EncryptionUtility::encrypt($word));
206 }
207
208 // Store the session data
209 //$wordRepository->setWord($this->word);
210
211 // Build the image
212 $image = $this->buildImage($word, $this->settings['imageWidth'], $this->settings['imageHeight'], $this->settings['backgroundType']);
213
214 // Send the image
215 \SJBR\SrFreecap\Utility\ImageContentUtility::sendImage($image, $this->settings['imageFormat']);
216
217 // Cleanup
218 ImageDestroy($image);
219
220 // Return an empty string
221 return '';
222 }
223
224 /**
225 * Builds the CAPTCHA image
226 *
227 * @return string GD image identifier of image
228 */
229 protected function buildImage ($word, $width, $height, $backgroundType) {
230
231 $image = ImageCreate($width, $height);
232 $background = ImageColorAllocate($image, 254, 254, 254);
233
234 // Write word on image
235 $image = \SJBR\SrFreecap\Utility\ImageContentUtility::writeWordOnImage($width, $height, $word, $this->settings['textColor'], $this->settings['textPosition'], $this->settings['colorMaximum'], $backgroundType, $this->settings['fontLocations'], $this->settings['fontWidths'], $this->settings['morphFactor']);
236
237 // Blur edges
238 // Doesn't really add any security, but looks a lot nicer, and renders text a little easier to read
239 // for humans (hopefully not for OCRs, but if you know better, feel free to disable this function)
240 // (and if you do, let me know why)
241 $image = \SJBR\SrFreecap\Utility\ImageContentUtility::blurImage($image);
242
243 if ($this->settings['imageFormat'] != 'jpg' && $backgroundType == \SJBR\SrFreecap\Utility\ImageContentUtility::BACKGROUND_TYPE_TRANSPARENT) {
244 // Make background transparent
245 ImageColorTransparent($image, $background);
246 }
247
248 // Try to avoid 'free p*rn' style CAPTCHA re-use
249 // ('*'ed to stop my site coming up for certain keyword searches on google)
250 // can obscure CAPTCHA word in some cases..
251 // Write site tags 'shining through' the morphed image
252 /*if (count($this->settings['siteTag'])) {
253 $image2 = \SJBR\SrFreecap\Utility\ImageContentUtility::writeSiteTags($width, $height, $this->settings['siteTag'], $this->settings['siteTagPosition']);
254 ImageCopyMerge($image2, $image, 0, 0, 0, 0, $width, $height, 80);
255 ImageCopy($image, $image2, 0, 0, 0, 0, $width, $height);
256 ImageDestroy($image2);
257 }*/
258
259 if ($backgroundType != \SJBR\SrFreecap\Utility\ImageContentUtility::BACKGROUND_TYPE_TRANSPARENT) {
260 // Get noisy background
261 $image3 = \SJBR\SrFreecap\Utility\ImageContentUtility::generateNoisyBackground($width, $height, $word, $backgroundType, $this->settings['backgroundImages'], $this->settings['backgroundMorph'], $this->settings['backgroundBlur']);
262 // Merge with obfuscated background
263 $image = \SJBR\SrFreecap\Utility\ImageContentUtility::mergeCaptchaWithBackground($width, $height, $image, $image3, $backgroundType, $this->settings['mergeWithBackground']);
264 ImageDestroy($image3);
265 }
266
267 return $image;
268 }
269 }
270 class_alias('SJBR\SrFreecap\View\ImageGenerator\ShowPng', 'Tx_SrFreecap_View_ImageGenerator_ShowPng');
271 ?>