Initial commit - Typo3 11.5.41
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Configuration;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2013-2020 Stanislas Rolland <typo32020(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
|
||||
|
||||
/**
|
||||
* Class providing configuration help for extension SrFreecap
|
||||
*/
|
||||
class ConfigurationHelper
|
||||
{
|
||||
/**
|
||||
* Renders a select element that allows to choose the encryption algoritm to be used by the extension
|
||||
*
|
||||
* @param array $params: Field information to be rendered
|
||||
* @param AbstractTagBasedViewHelper $pObj: The calling parent object.
|
||||
* @return string The HTML select field
|
||||
*/
|
||||
public function buildEncryptionAlgorithmSelector(array $params, AbstractTagBasedViewHelper $pObj)
|
||||
{
|
||||
if (in_array('openssl', get_loaded_extensions())) {
|
||||
$encryptionAlgorithms = openssl_get_cipher_methods(true);
|
||||
if (!empty($encryptionAlgorithms)) {
|
||||
$field = '<br /><select id="' . $params['propertyName'] . '" name="' . $params['fieldName'] . '" >' . LF;
|
||||
foreach ($encryptionAlgorithms as $encryptionAlgorithm) {
|
||||
$selected = $params['fieldValue'] == $encryptionAlgorithm ? 'selected="selected"' : '';
|
||||
$field .= '<option name="' . $encryptionAlgorithm . '" value="' . $encryptionAlgorithm . '" ' . $selected . '>' . $encryptionAlgorithm . '</option>' . LF;
|
||||
}
|
||||
$field .= '</select><br /><br />' . LF;
|
||||
} else {
|
||||
$field = '<br />Available encryption algorithms could not be found. Algorithm AES-256-CBC will be used.<br />';
|
||||
}
|
||||
} else {
|
||||
$field = '<br />PHP openssl extension is not available.<br />';
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Controller;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2021 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use SJBR\SrFreecap\Domain\Repository\WordRepository;
|
||||
use SJBR\SrFreecap\View\AudioPlayer\PlayMp3;
|
||||
use SJBR\SrFreecap\View\AudioPlayer\PlayWav;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
/**
|
||||
* Renders a wav audio version of the CAPTCHA
|
||||
*/
|
||||
class AudioPlayerController extends ActionController
|
||||
{
|
||||
/**
|
||||
* @var string Name of the extension this controller belongs to
|
||||
*/
|
||||
protected $extensionName = 'SrFreecap';
|
||||
|
||||
/**
|
||||
* @var WordRepository
|
||||
*/
|
||||
protected $wordRepository;
|
||||
|
||||
/**
|
||||
* Dependency injection of the Word Repository
|
||||
*
|
||||
* @param WordRepository $wordRepository
|
||||
*/
|
||||
public function injectWordRepository(WordRepository $wordRepository)
|
||||
{
|
||||
$this->wordRepository = $wordRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Play the audio catcha
|
||||
*
|
||||
* @return string Audio content to be sent to the client
|
||||
*/
|
||||
public function playAction()
|
||||
{
|
||||
$word = $this->wordRepository->getWord();
|
||||
$format = $this->request->getFormat();
|
||||
if ($format === 'mp3') {
|
||||
$this->view = GeneralUtility::makeInstance(PlayMp3::class);
|
||||
} else if ($format === 'wav') {
|
||||
$this->view = GeneralUtility::makeInstance(PlayWav::class);
|
||||
} else {
|
||||
throw new \Exception('Unknow audio format ' . $format);
|
||||
}
|
||||
$this->view->assign('word', $word);
|
||||
$this->view->render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Controller;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2021 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use SJBR\SrFreecap\Domain\Model\Font;
|
||||
use SJBR\SrFreecap\Domain\Repository\FontRepository;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
/**
|
||||
* Font Maker controller
|
||||
*/
|
||||
class FontMakerController extends ActionController
|
||||
{
|
||||
/**
|
||||
* @var string Name of the extension this controller belongs to
|
||||
*/
|
||||
protected $extensionName = 'SrFreecap';
|
||||
|
||||
/**
|
||||
* Display the font maker form
|
||||
*
|
||||
* @param Font $font
|
||||
* @return string An HTML form for creating a new font
|
||||
*/
|
||||
public function newAction(Font $font = null)
|
||||
{
|
||||
if (!is_object($font)) {
|
||||
$font = new Font();
|
||||
}
|
||||
$this->view->assign('font', $font);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the font file and display the result
|
||||
*
|
||||
* @param Font $font
|
||||
* @return string HTML presenting the new font that was created
|
||||
*/
|
||||
public function createAction(Font $font)
|
||||
{
|
||||
// Create the font data
|
||||
$font->createGdFontFile();
|
||||
// Store the GD font file
|
||||
$fontRepository = GeneralUtility::makeInstance(FontRepository::class);
|
||||
$fontRepository->writeFontFile($font);
|
||||
$this->view->assign('font', $font);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Controller;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2022 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use SJBR\SrFreecap\Domain\Repository\WordRepository;
|
||||
use SJBR\SrFreecap\View\ImageGenerator\ShowPng;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* Renders the CAPTCHA image
|
||||
*/
|
||||
class ImageGeneratorController extends ActionController
|
||||
{
|
||||
/**
|
||||
* @var string Name of the extension this controller belongs to
|
||||
*/
|
||||
protected $extensionName = 'SrFreecap';
|
||||
|
||||
/**
|
||||
* @var string Name of the extension this controller belongs to
|
||||
*/
|
||||
protected $extensionKey = 'sr_freecap';
|
||||
|
||||
/**
|
||||
* @var WordRepository
|
||||
*/
|
||||
protected $wordRepository;
|
||||
|
||||
/**
|
||||
* Dependency injection of the Word Repository
|
||||
*
|
||||
* @param WordRepository $wordRepository
|
||||
*/
|
||||
public function injectWordRepository(WordRepository $wordRepository)
|
||||
{
|
||||
$this->wordRepository = $wordRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the CAPTCHA image
|
||||
*/
|
||||
public function showAction()
|
||||
{
|
||||
// Get session data
|
||||
$word = $this->wordRepository->getWord();
|
||||
// Which type of hash to use
|
||||
// Store in session so can validate in form processor
|
||||
$word->setHashFunction('md5');
|
||||
$this->view = GeneralUtility::makeInstance(ShowPng::class);
|
||||
$this->view->assign('word', $word);
|
||||
// Adjust settings
|
||||
$this->processSettings();
|
||||
$this->view->assign('settings', $this->settings);
|
||||
// Render the captcha image
|
||||
$this->view->render();
|
||||
// Store the session data
|
||||
$this->wordRepository->setWord($word);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reviews and adjusts plugin settings
|
||||
*/
|
||||
protected function processSettings()
|
||||
{
|
||||
// Image type:
|
||||
// possible values: "jpg", "png", "gif"
|
||||
// jpg doesn't support transparency (transparent bg option ends up white)
|
||||
// png isn't supported by old browsers (see http://www.libpng.org/pub/png/pngstatus.html)
|
||||
// gif may not be supported by your GD Lib.
|
||||
$this->settings['imageFormat'] = (isset($this->settings['imageFormat']) && $this->settings['imageFormat']) ? $this->settings['imageFormat'] : 'png';
|
||||
|
||||
// true = generate pseudo-random string, false = use dictionary
|
||||
// dictionary is easier to recognise
|
||||
// - both for humans and computers, so use random string if you're paranoid.
|
||||
$this->settings['useWordsList'] = (isset($this->settings['useWordsList']) && $this->settings['useWordsList']) ? true : false;
|
||||
|
||||
// if your server is NOT set up to deny web access to files beginning ".ht"
|
||||
// then you should ensure the dictionary file is kept outside the web directory
|
||||
// eg: if www.foo.com/index.html points to c:\website\www\index.html
|
||||
// then the dictionary should be placed in c:\website\dict.txt
|
||||
// test your server's config by trying to access the dictionary through a web browser
|
||||
// you should NOT be able to view the contents.
|
||||
// can leave this blank if not using dictionary
|
||||
$this->settings['wordsListLocation'] = \SJBR\SrFreecap\Utility\LocalizationUtility::getWordsListLocation($this->settings['defaultWordsList'] ?? '');
|
||||
|
||||
// Used for non-dictionary word generation and to calculate image width
|
||||
$this->settings['maxWordLength'] = (isset($this->settings['maxWordLength']) && $this->settings['maxWordLength']) ? $this->settings['maxWordLength'] : 6;
|
||||
|
||||
// Maximum times a user can refresh the image
|
||||
// on a 6500 word dictionary, I think 15-50 is enough to not annoy users and make BF unfeasble.
|
||||
// further notes re: BF attacks in "avoid brute force attacks" section, below
|
||||
// on the other hand, those attempting OCR will find the ability to request new images
|
||||
// very useful; if they can't crack one, just grab an easier target...
|
||||
// for the ultra-paranoid, setting it to <5 will still work for most users
|
||||
$this->settings['maxAttempts'] = (isset($this->settings['maxAttempts']) && $this->settings['maxAttempts']) ? $this->settings['maxAttempts'] : 50;
|
||||
|
||||
// List of fonts to use
|
||||
// font size should be around 35 pixels wide for each character.
|
||||
// you can use my GD fontmaker script at www.puremango.co.uk to create your own fonts
|
||||
// There are other programs to can create GD fonts, but my script allows a greater
|
||||
// degree of control over exactly how wide each character is, and is therefore
|
||||
// recommended for 'special' uses. For normal use of GD fonts,
|
||||
// the GDFontGenerator @ http://www.philiplb.de is excellent for convering ttf to GD
|
||||
// the fonts included with freeCap *only* include lowercase alphabetic characters
|
||||
// so are not suitable for most other uses
|
||||
// to increase security, you really should add other fonts
|
||||
if ($this->settings['generateNumbers'] ?? false) {
|
||||
$this->settings['fontLocations'] = ['EXT:' . $this->extensionKey . '/Resources/Private/Captcha/Fonts/anonymous.gdf'];
|
||||
} else {
|
||||
$this->settings['fontLocations'] = [
|
||||
'EXT:' . $this->extensionKey . '/Resources/Private/Captcha/Fonts/freecap_font1.gdf',
|
||||
'EXT:' . $this->extensionKey . '/Resources/Private/Captcha/Fonts/freecap_font2.gdf',
|
||||
'EXT:' . $this->extensionKey . '/Resources/Private/Captcha/Fonts/freecap_font3.gdf',
|
||||
'EXT:' . $this->extensionKey . '/Resources/Private/Captcha/Fonts/freecap_font4.gdf',
|
||||
'EXT:' . $this->extensionKey . '/Resources/Private/Captcha/Fonts/freecap_font5.gdf'
|
||||
];
|
||||
}
|
||||
if ($this->settings['fontFiles'] ?? false) {
|
||||
$this->settings['fontLocations'] = GeneralUtility::trimExplode(',', $this->settings['fontFiles'], 1);
|
||||
}
|
||||
for ($i = 0; $i < sizeof($this->settings['fontLocations']); $i++) {
|
||||
if (substr($this->settings['fontLocations'][$i],0,4) == 'EXT:') {
|
||||
$this->settings['fontLocations'][$i] = GeneralUtility::getFileAbsFileName($this->settings['fontLocations'][$i]);
|
||||
} else {
|
||||
$this->settings['fontLocations'][$i] = Environment::getPublicPath() . '/uploads/' . ExtensionManagementUtility::getCN($this->extensionKey) . '/' . $this->settings['fontLocations'][$i];
|
||||
}
|
||||
}
|
||||
|
||||
// Text color
|
||||
// 0 = one random color for all letters
|
||||
// 1 = different random color for each letter
|
||||
if ($this->settings['textColor'] ?? false) {
|
||||
$this->settings['textColor'] = 1;
|
||||
} else {
|
||||
$this->settings['textColor'] = 0;
|
||||
}
|
||||
|
||||
// Text position
|
||||
$this->settings['textPosition'] = [];
|
||||
$this->settings['textPosition']['horizontal'] = isset($this->settings['textHorizontalPosition']) ? (int)$this->settings['textHorizontalPosition'] : 32;
|
||||
$this->settings['textPosition']['vertical'] = isset($this->settings['textVerticalPosition']) ? (int)$this->settings['textVerticalPosition'] : 15;
|
||||
// Text morphing factor
|
||||
$this->settings['morphFactor'] = (isset($this->settings['morphFactor']) && $this->settings['morphFactor']) ? (int)$this->settings['morphFactor'] : 0;
|
||||
// Limits for text color
|
||||
$this->settings['colorMaximum'] = [];
|
||||
if (isset($this->settings['colorMaximumDarkness'])) {
|
||||
$this->settings['colorMaximum']['darkness'] = (int)$this->settings['colorMaximumDarkness'];
|
||||
}
|
||||
if (isset($this->settings['colorMaximumLightness'])) {
|
||||
$this->settings['colorMaximum']['lightness'] = (int)$this->settings['colorMaximumLightness'];
|
||||
}
|
||||
|
||||
// Background
|
||||
// Many thanks to http://ocr-research.org.ua and http://sam.zoy.org/pwntcha/ for testing
|
||||
// for jpgs, 'transparent' is white
|
||||
if (!isset($this->settings['backgroundType']) || !in_array($this->settings['backgroundType'], ['Transparent', 'White with grid', 'White with squiggles', 'Morphed image blocks'])) {
|
||||
$this->settings['backgroundType'] = 'White with grid';
|
||||
}
|
||||
// Should we blur the background? (looks nicer, makes text easier to read, takes longer)
|
||||
$this->settings['backgroundBlur'] = ((isset($this->settings['backgroundBlur']) && $this->settings['backgroundBlur']) || !isset($this->settings['backgroundBlur'])) ? true : false;
|
||||
// For background type 'Morphed image blocks', which images should we use?
|
||||
// If you add your own, make sure they're fairly 'busy' images (ie a lot of shapes in them)
|
||||
$this->settings['backgroundImages'] = [
|
||||
'EXT:' . $this->extensionKey . '/Resources/Private/Captcha/Images/freecap_im1.jpg',
|
||||
'EXT:' . $this->extensionKey . '/Resources/Private/Captcha/Images/freecap_im2.jpg',
|
||||
'EXT:' . $this->extensionKey . '/Resources/Private/Captcha/Images/freecap_im3.jpg',
|
||||
'EXT:' . $this->extensionKey . '/Resources/Private/Captcha/Images/freecap_im4.jpg',
|
||||
'EXT:' . $this->extensionKey . '/Resources/Private/Captcha/Images/freecap_im5.jpg'
|
||||
];
|
||||
// For non-transparent backgrounds only:
|
||||
// if 0, merges CAPTCHA with background
|
||||
// if 1, write CAPTCHA over background
|
||||
$this->settings['mergeWithBackground'] = (isset($this->settings['mergeWithBackground']) && $this->settings['mergeWithBackground']) ? 0 : 1;
|
||||
// Should we morph the background? (recommend yes, but takes a little longer to compute)
|
||||
$this->settings['backgroundMorph'] = (isset($this->settings['backgroundMorph']) && $this->settings['backgroundMorph']) ? true : false;
|
||||
|
||||
// Read each font and get font character widths
|
||||
$this->settings['fontWidths'] = [];
|
||||
for ($i=0 ; $i < sizeof($this->settings['fontLocations']); $i++) {
|
||||
$handle = fopen($this->settings['fontLocations'][$i],"r");
|
||||
// Read header of GD font, up to char width
|
||||
$c_wid = fread($handle,12);
|
||||
$this->settings['fontWidths'][$i] = ord($c_wid[8])+ord($c_wid[9])+ord($c_wid[10])+ord($c_wid[11]);
|
||||
fclose($handle);
|
||||
}
|
||||
// Modify image width depending on maximum possible length of word
|
||||
// you shouldn't need to use words > 6 chars in length really.
|
||||
$this->settings['imageWidth'] = ($this->settings['maxWordLength'] * (array_sum($this->settings['fontWidths'])/sizeof($this->settings['fontWidths']))) + (isset($this->settings['imageAdditionalWidth']) ? (int)$this->settings['imageAdditionalWidth'] : 40);
|
||||
$this->settings['imageHeight'] = (isset($this->settings['imageHeight']) && $this->settings['imageHeight']) ? (int)$this->settings['imageHeight'] : 90;
|
||||
|
||||
// Try to avoid the 'free p*rn' method of CAPTCHA circumvention
|
||||
// see www.wikipedia.com/captcha for more info
|
||||
// "To avoid spam, please do NOT enter the text if this site is not example.org";
|
||||
// or more simply:
|
||||
// "for use only on example.org";
|
||||
// reword or add lines as you please
|
||||
$this->settings['siteTag'] = (isset($this->settings['siteTag']) && $this->settings['siteTag']) ? explode('|', LocalizationUtility::translate('site_tag', $this->extensionName, [(isset($this->settings['siteTagDomain']) && $this->settings['siteTagDomain']) ? $this->settings['siteTagDomain'] : 'example.org'])) : [];
|
||||
|
||||
// where to write the above:
|
||||
// 0=top
|
||||
// 1=bottom
|
||||
// 2=both
|
||||
$this->settings['siteTagPosition'] = isset($this->settings['siteTagPosition']) ? (int)$this->settings['siteTagPosition'] : 1;
|
||||
}
|
||||
}
|
||||
230
typo3conf/ext/sr_freecap/Classes/Domain/Model/Font.php
Normal file
230
typo3conf/ext/sr_freecap/Classes/Domain/Model/Font.php
Normal file
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Domain\Model;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2022 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use SJBR\SrFreecap\Utility\FontMakingUtility;
|
||||
use SJBR\SrFreecap\Validation\Validator\TtfFileValidator;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Extbase\Annotation\Validate;
|
||||
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
|
||||
|
||||
/**
|
||||
* Font object
|
||||
*
|
||||
* This file must be iso-8859-2-encoded!
|
||||
*
|
||||
*/
|
||||
class Font extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $charactersIncludedInFont;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @Validate("NumberRange", options={"minimum": 5, "maximum": 255})
|
||||
*/
|
||||
protected $characterWidth;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @Validate("NumberRange", options={"minimum": 5, "maximum": 255})
|
||||
*/
|
||||
protected $characterHeight;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
**/
|
||||
protected $endianness;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @Validate("NotEmpty")
|
||||
* @Validate("StringLength", options={"minimum": 1, "maximum": 255})
|
||||
* @Validate("\SJBR\SrFreecap\Validation\Validator\TtfFileValidator")
|
||||
**/
|
||||
protected $ttfFontFileName = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
**/
|
||||
protected $gdFontFilePrefix = 'font';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
**/
|
||||
protected $pngImageFileName = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
**/
|
||||
protected $gdFontData = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
**/
|
||||
protected $gdFontFileName = '';
|
||||
|
||||
public function __construct(
|
||||
$charactersIncludedInFont = 0,
|
||||
$characterWidth = 34,
|
||||
$characterHeight = 50,
|
||||
$endianness = 0,
|
||||
$ttfFontFileName = '',
|
||||
$gdFontFilePrefix = '',
|
||||
$pngImageFileName = '',
|
||||
$gdFontData = '',
|
||||
$gdFontFileName = ''
|
||||
) {
|
||||
$this->setCharactersIncludedInFont($charactersIncludedInFont);
|
||||
$this->setCharacterWidth($characterWidth);
|
||||
$this->setCharacterHeight($characterHeight);
|
||||
$this->setEndianness($endianness);
|
||||
$this->setTtfFontFileName($ttfFontFileName);
|
||||
$this->setGdFontFilePrefix($gdFontFilePrefix);
|
||||
$this->setPngImageFileName($pngImageFileName);
|
||||
$this->setGdFontData($gdFontData);
|
||||
$this->setGdFontFileName($gdFontFileName);
|
||||
}
|
||||
|
||||
public function setCharactersIncludedInFont($charactersIncludedInFont) {
|
||||
$this->charactersIncludedInFont = (int)$charactersIncludedInFont;
|
||||
}
|
||||
|
||||
public function getCharactersIncludedInFont() {
|
||||
return $this->charactersIncludedInFont;
|
||||
}
|
||||
|
||||
public function setCharacterWidth($characterWidth) {
|
||||
$this->characterWidth = (int)$characterWidth;
|
||||
}
|
||||
|
||||
public function getCharacterWidth() {
|
||||
return $this->characterWidth;
|
||||
}
|
||||
|
||||
public function setCharacterHeight($characterHeight) {
|
||||
$this->characterHeight = (int)$characterHeight;
|
||||
}
|
||||
|
||||
public function getCharacterHeight() {
|
||||
return $this->characterHeight;
|
||||
}
|
||||
|
||||
public function setEndianness($endianness) {
|
||||
$this->endianness = (int)$endianness;
|
||||
}
|
||||
|
||||
public function getEndianness() {
|
||||
return $this->endianness;
|
||||
}
|
||||
|
||||
public function setTtfFontFileName($ttfFontFileName) {
|
||||
$this->ttfFontFileName = (string)$ttfFontFileName;
|
||||
}
|
||||
|
||||
public function getTtfFontFileName() {
|
||||
return $this->ttfFontFileName;
|
||||
}
|
||||
|
||||
public function setGdFontFilePrefix($gdFontFilePrefix = 'font') {
|
||||
$this->gdFontFilePrefix = (string)$gdFontFilePrefix;
|
||||
}
|
||||
|
||||
public function getGdFontFilePrefix() {
|
||||
return $this->gdFontFilePrefix;
|
||||
}
|
||||
|
||||
|
||||
public function setPngImageFileName($pngImageFileName) {
|
||||
$this->pngImageFileName = (string)$pngImageFileName;
|
||||
}
|
||||
|
||||
public function getPngImageFileName() {
|
||||
return $this->pngImageFileName;
|
||||
}
|
||||
|
||||
public function setGdFontData($gdFontData) {
|
||||
$this->gdFontData = (string)$gdFontData;
|
||||
}
|
||||
|
||||
public function getGdFontdata() {
|
||||
return $this->gdFontData;
|
||||
}
|
||||
|
||||
public function setGdFontFileName($gdFontFileName) {
|
||||
$this->gdFontFileName = (string)$gdFontFileName;
|
||||
}
|
||||
|
||||
public function getGdFontFileName() {
|
||||
return $this->gdFontFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates teh GD font file
|
||||
*/
|
||||
public function createGdFontFile()
|
||||
{
|
||||
switch ($this->charactersIncludedInFont) {
|
||||
case 1:
|
||||
$characters = 'a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z';
|
||||
$startCharacter = 'a';
|
||||
break;
|
||||
case 2:
|
||||
$characters = 'a,b,c,d,e,f,g,h,i,j,k,l,m,n,o'
|
||||
.',p,q,r,s,t,u,v,w,x,y,z,-,-,-,-,-'
|
||||
.',-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-'
|
||||
.',-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-'
|
||||
.',-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-'
|
||||
.',-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-'
|
||||
.',-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-'
|
||||
.',-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,ß'
|
||||
.',à,á,â,ă,ä,Í,ć,ç,č,é,ę,ë,ě,Í,î,ď'
|
||||
.',đ,ń,ň,ó,ô,ő,ö,-,ř,ů,ú,ű,ü,ý,ţ,-';
|
||||
$startCharacter = 'a';
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
$characters = '0,1,2,3,4,5,6,7,8,9';
|
||||
$startCharacter = '0';
|
||||
break;
|
||||
}
|
||||
$numberOfCharacters = count(explode(',', $characters));
|
||||
$this->setPngImageFileName(FontMakingUtility::makeFontImage($characters, $this->ttfFontFileName, $this->characterWidth, $this->characterHeight));
|
||||
if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'] ?? false) {
|
||||
$image = @ImageCreateFromPNG(Environment::getPublicPath() . '/' . $this->pngImageFileName);
|
||||
} else {
|
||||
$image = @ImageCreateFromGIF(Environment::getPublicPath() . '/' . $this->pngImageFileName);
|
||||
}
|
||||
if ($image !== false) {
|
||||
$this->setGdFontdata(FontMakingUtility::makeFont($image, $numberOfCharacters, $startCharacter, $this->characterWidth, $this->characterHeight, $this->endianness));
|
||||
ImageDestroy($image);
|
||||
}
|
||||
}
|
||||
}
|
||||
109
typo3conf/ext/sr_freecap/Classes/Domain/Model/Word.php
Normal file
109
typo3conf/ext/sr_freecap/Classes/Domain/Model/Word.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Domain\Model;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2020 Stanislas Rolland <typo32020(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
|
||||
|
||||
/**
|
||||
* Word object
|
||||
*/
|
||||
class Word extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $wordHash;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $hashFunction;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $wordCypher;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $attempts;
|
||||
|
||||
public function __construct(
|
||||
$wordHash = '',
|
||||
$hashFunction = 'md5',
|
||||
$wordCypher = array(),
|
||||
$attempts = 0
|
||||
)
|
||||
{
|
||||
$this->setWordHash($wordHash);
|
||||
$this->setHashFunction($hashFunction);
|
||||
$this->setWordCypher($wordCypher);
|
||||
$this->setAttempts($attempts);
|
||||
}
|
||||
|
||||
public function setWordHash($wordHash)
|
||||
{
|
||||
$this->wordHash = (string)$wordHash;
|
||||
}
|
||||
|
||||
public function getWordHash()
|
||||
{
|
||||
return $this->wordHash;
|
||||
}
|
||||
|
||||
public function setHashFunction($hashFunction)
|
||||
{
|
||||
$this->hashFunction = (string)$hashFunction;
|
||||
}
|
||||
|
||||
public function getHashFunction()
|
||||
{
|
||||
return $this->hashFunction;
|
||||
}
|
||||
|
||||
public function setWordCypher($wordCypher)
|
||||
{
|
||||
$this->wordCypher = (array)$wordCypher;
|
||||
}
|
||||
|
||||
public function getWordCypher()
|
||||
{
|
||||
return $this->wordCypher;
|
||||
}
|
||||
|
||||
public function setAttempts($attempts)
|
||||
{
|
||||
$this->attempts = (int)$attempts;
|
||||
}
|
||||
|
||||
public function getAttempts()
|
||||
{
|
||||
return $this->attempts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Domain\Repository;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2018 Stanislas Rolland <typo3@sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use SJBR\SrFreecap\Domain\Model\Font;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Persistence\Repository;
|
||||
|
||||
/**
|
||||
* Font repository
|
||||
*/
|
||||
class FontRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* @var string Name of the extension this controller belongs to
|
||||
*/
|
||||
protected $extensionKey = 'sr_freecap';
|
||||
|
||||
/**
|
||||
* Writes the GD font file
|
||||
*
|
||||
* @param Font the object to be stored
|
||||
* @return \SJBR\SrFreecap\Domain\Repository\FontRepository $this
|
||||
*/
|
||||
public function writeFontFile(Font $font)
|
||||
{
|
||||
$directory = Environment::getPublicPath() . '/' . 'uploads/' . ExtensionManagementUtility::getCN($this->extensionKey) . '/';
|
||||
GeneralUtility::mkdir_deep($directory);
|
||||
$fileName = $directory . $font->getGdFontFilePrefix() . '_' . md5($font->getGdFontData()) . '.gdf';
|
||||
if (GeneralUtility::writeFile($fileName, $font->getGdFontData())) {
|
||||
$font->setGdFontFileName($fileName);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Domain\Repository;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2021 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use SJBR\SrFreecap\Domain\Model\Word;
|
||||
use SJBR\SrFreecap\Domain\Session\SessionStorage;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Persistence\Repository;
|
||||
|
||||
/**
|
||||
* Word repository in session storage
|
||||
*/
|
||||
class WordRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* The session sorage handler
|
||||
* @var SessionStorage
|
||||
*/
|
||||
protected $sessionStorage;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct(SessionStorage $sessionStorage)
|
||||
{
|
||||
// Get an instance of the session storage handler
|
||||
$this->sessionStorage = $sessionStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object stored in the user's session
|
||||
*
|
||||
* @return Word the stored object
|
||||
*/
|
||||
public function getWord()
|
||||
{
|
||||
$word = $this->sessionStorage->restoreFromSession();
|
||||
// If no Word object is found in session data, initialize a new one
|
||||
if (!is_object($word)) {
|
||||
$word = new Word();
|
||||
}
|
||||
return $word;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the object into the user's session
|
||||
*
|
||||
* @param Word the object to be stored
|
||||
* @return WordRepository
|
||||
*/
|
||||
public function setWord(Word $object)
|
||||
{
|
||||
$this->sessionStorage->writeToSession($object);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the session: removes the stored object from the user's session
|
||||
*
|
||||
* @return WordRepository
|
||||
*/
|
||||
public function cleanUpWord()
|
||||
{
|
||||
$this->sessionStorage->cleanUpSession();
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Domain\Session;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2021 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Session\UserSession;
|
||||
use TYPO3\CMS\Core\Session\UserSessionManager;
|
||||
use TYPO3\CMS\Core\Session\Backend\Exception\SessionNotFoundException;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
|
||||
|
||||
/**
|
||||
* Session storage
|
||||
*/
|
||||
class SessionStorage implements SingletonInterface
|
||||
{
|
||||
const SESSIONNAMESPACE = 'tx_srfreecap';
|
||||
|
||||
/**
|
||||
* Returns the object stored in the user's PHP session
|
||||
*
|
||||
* @return Object the stored object
|
||||
*/
|
||||
public function restoreFromSession()
|
||||
{
|
||||
$sessionData = $this->getUser()->getSessionData(self::SESSIONNAMESPACE);
|
||||
if ($sessionData === null) {
|
||||
return null;
|
||||
}
|
||||
return unserialize($sessionData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an object into the PHP session
|
||||
*
|
||||
* @param $object any serializable object to store into the session
|
||||
* @return SessionStorage
|
||||
*/
|
||||
public function writeToSession($object)
|
||||
{
|
||||
$sessionData = serialize($object);
|
||||
$this->getUser()->setAndSaveSessionData(self::SESSIONNAMESPACE, $sessionData);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the session: removes the stored object from the PHP session
|
||||
*
|
||||
* @return SessionStorage
|
||||
*/
|
||||
public function cleanUpSession()
|
||||
{
|
||||
$this->getUser()->setAndSaveSessionData(self::SESSIONNAMESPACE, null);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a frontend user session
|
||||
*
|
||||
* @return User The current frontend user object
|
||||
*/
|
||||
protected function getUser() : FrontendUserAuthentication
|
||||
{
|
||||
if (!isset($GLOBALS['TSFE']) || !$GLOBALS['TSFE']->fe_user) {
|
||||
throw new SessionNotFoundException('No frontend user found in session!');
|
||||
}
|
||||
return $GLOBALS['TSFE']->fe_user;
|
||||
}
|
||||
}
|
||||
275
typo3conf/ext/sr_freecap/Classes/Http/EidDispatcher.php
Normal file
275
typo3conf/ext/sr_freecap/Classes/Http/EidDispatcher.php
Normal file
@@ -0,0 +1,275 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Http;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* 2010 Daniel Lienert <daniel@lienert.cc>, Michael Knoll <mimi@kaktusteam.de>
|
||||
* 2012-2022 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Error\Http\BadRequestException;
|
||||
use TYPO3\CMS\Core\Http\NullResponse;
|
||||
use TYPO3\CMS\Core\Localization\Locales;
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\RootlineUtility;
|
||||
use TYPO3\CMS\Extbase\Core\Bootstrap;
|
||||
use TYPO3\CMS\Extbase\Mvc\Dispatcher;
|
||||
use TYPO3\CMS\Extbase\Mvc\Request;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
/**
|
||||
* Dispatch the eid request
|
||||
*/
|
||||
class EidDispatcher
|
||||
{
|
||||
/**
|
||||
* Array of all request Arguments
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $requestArguments = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $vendorName = 'SJBR';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $extensionName = 'SrFreecap';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $pluginName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $controllerName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $actionName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $formatName;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $arguments = [];
|
||||
|
||||
/**
|
||||
* Initializes and dispatches actions
|
||||
* Call this function if you want to use this dispatcher "standalone"
|
||||
* @param ServerRequestInterface $request
|
||||
* @return Response
|
||||
*/
|
||||
public function initAndDispatch($request)
|
||||
{
|
||||
return $this->initTypoScriptConfiguration($request)
|
||||
->initLanguage($request)
|
||||
->initCallArguments()
|
||||
->dispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an extbase context and returns the response
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
protected function dispatch()
|
||||
{
|
||||
$bootstrap = GeneralUtility::makeInstance(Bootstrap::class);
|
||||
$configuration['vendorName'] = $this->vendorName;
|
||||
$configuration['extensionName'] = $this->extensionName;
|
||||
$configuration['pluginName'] = $this->pluginName;
|
||||
$bootstrap->initialize($configuration);
|
||||
$request = $this->buildRequest();
|
||||
try {
|
||||
$response = GeneralUtility::makeInstance(Dispatcher::class)->dispatch($request);
|
||||
} catch (\Exception $e) {
|
||||
throw new BadRequestException('An argument is missing or invalid', 1394587024);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TypoScript configuration
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @return EidDispatcher
|
||||
*/
|
||||
protected function initTypoScriptConfiguration($request)
|
||||
{
|
||||
$controller = $request->getAttribute('frontend.controller');
|
||||
$controller->type = 0;
|
||||
$context = $controller->getContext();
|
||||
$controller->rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $controller->id, $controller->MP, $context)->get();
|
||||
$controller->getConfigArray();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set language and locale
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @return EidDispatcher
|
||||
*/
|
||||
protected function initLanguage($request)
|
||||
{
|
||||
$controller = $request->getAttribute('frontend.controller');
|
||||
$siteLanguage = $controller->getLanguage();
|
||||
$locales = GeneralUtility::makeInstance(Locales::class);
|
||||
$locales->setSystemLocaleFromSiteLanguage($siteLanguage);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a request object
|
||||
*
|
||||
* @return Request $request
|
||||
*/
|
||||
protected function buildRequest()
|
||||
{
|
||||
$controllerClassName = $this->vendorName . '\\' . $this->extensionName . '\\' . 'Controller' . '\\' . $this->pluginName . 'Controller';
|
||||
$request = GeneralUtility::makeInstance(Request::class, $controllerClassName);
|
||||
$request->setControllerObjectName($controllerClassName);
|
||||
$request->setPluginName($this->pluginName);
|
||||
$request->setControllerActionName($this->actionName);
|
||||
$request->setFormat($this->formatName);
|
||||
$request->setArguments($this->arguments);
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the call arguments
|
||||
*
|
||||
* @return EidDispatcher
|
||||
*/
|
||||
public function initCallArguments() {
|
||||
$request = GeneralUtility::_GP('request');
|
||||
if ($request) {
|
||||
$this->setRequestArgumentsFromJSON($request);
|
||||
} else {
|
||||
$this->setRequestArgumentsFromGetPost();
|
||||
}
|
||||
return $this->setPluginName($this->requestArguments['pluginName'])
|
||||
->setControllerName()
|
||||
->setActionName($this->requestArguments['actionName'])
|
||||
->setFormatName($this->requestArguments['formatName'])
|
||||
->setArguments($this->requestArguments['arguments'] ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the request array from JSON
|
||||
*
|
||||
* @param string $request
|
||||
*/
|
||||
protected function setRequestArgumentsFromJSON($request)
|
||||
{
|
||||
$requestArray = json_decode($request, true);
|
||||
if (is_array($requestArray)) {
|
||||
ArrayUtility::mergeRecursiveWithOverrule($this->requestArguments, $requestArray);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the request array from the getPost array
|
||||
*/
|
||||
protected function setRequestArgumentsFromGetPost()
|
||||
{
|
||||
$validArguments = ['pluginName', 'actionName', 'formatName', 'arguments'];
|
||||
foreach ($validArguments as $argument) {
|
||||
if (GeneralUtility::_GP($argument) ?? false) {
|
||||
$this->requestArguments[$argument] = GeneralUtility::_GP($argument);
|
||||
} else if (GeneralUtility::_GP('amp;' . $argument) ?? false) {
|
||||
// Something went wrong...
|
||||
$this->requestArguments[$argument] = GeneralUtility::_GP('amp;' . $argument);
|
||||
} else if ($argument !== 'arguments') {
|
||||
throw new BadRequestException('An argument is missing', 1394587023);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pluginName
|
||||
* @return EidDispatcher
|
||||
*/
|
||||
protected function setPluginName($pluginName = 'ImageGenerator')
|
||||
{
|
||||
$this->pluginName = htmlspecialchars((string)$pluginName);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EidDispatcher
|
||||
*/
|
||||
protected function setControllerName()
|
||||
{
|
||||
$this->controllerName = $this->pluginName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $actionName
|
||||
* @return EidDispatcher
|
||||
*/
|
||||
protected function setActionName($actionName = 'show')
|
||||
{
|
||||
$this->actionName = htmlspecialchars((string)$actionName);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $formatName
|
||||
* @return EidDispatcher
|
||||
*/
|
||||
protected function setFormatName($formatName = 'txt')
|
||||
{
|
||||
$this->formatName = htmlspecialchars((string)$formatName);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @return EidDispatcher
|
||||
*/
|
||||
protected function setArguments($arguments)
|
||||
{
|
||||
if (!is_array($arguments)) {
|
||||
$this->arguments = [];
|
||||
} else {
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
85
typo3conf/ext/sr_freecap/Classes/Middleware/EidHandler.php
Normal file
85
typo3conf/ext/sr_freecap/Classes/Middleware/EidHandler.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace SJBR\SrFreecap\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use TYPO3\CMS\Core\Http\DispatcherInterface;
|
||||
use TYPO3\CMS\Core\Http\NullResponse;
|
||||
use TYPO3\CMS\Core\Http\Response;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Lightweight alternative to regular frontend requests; used when $_GET[eID] is set.
|
||||
* In the future, logic from the EidUtility will be moved to this class, however in most cases
|
||||
* a custom PSR-15 middleware will be better suited for whatever job the eID functionality does currently.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class EidHandler implements MiddlewareInterface
|
||||
{
|
||||
/**
|
||||
* @var DispatcherInterface
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* @param DispatcherInterface $dispatcher
|
||||
*/
|
||||
public function __construct(DispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->dispatcher = $dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the request to the corresponding eID class or eID script
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @param RequestHandlerInterface $handler
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$eID = $request->getParsedBody()['eIDSR'] ?? $request->getQueryParams()['eIDSR'] ?? null;
|
||||
|
||||
if ($eID === null) {
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
// Remove any output produced until now
|
||||
ob_clean();
|
||||
|
||||
/** @var Response $response */
|
||||
$response = new Response();
|
||||
if (empty($eID) || !isset($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['sr_freecap']['eIDSR_include'][$eID])) {
|
||||
$response = $response->withStatus(404, 'eIDSR not registered');
|
||||
} else {
|
||||
$configuration = $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['sr_freecap']['eIDSR_include'][$eID];
|
||||
$response = new NullResponse();
|
||||
// Simple check to make sure that it's not an absolute file (to use the fallback)
|
||||
if (strpos($configuration, '::') !== false || is_callable($configuration)) {
|
||||
$frontendUser = $request->getAttribute('frontend.user');
|
||||
$request = $request->withAttribute('target', $configuration);
|
||||
$response = $this->dispatcher->dispatch($request);
|
||||
}
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
88
typo3conf/ext/sr_freecap/Classes/PiBaseApi.php
Normal file
88
typo3conf/ext/sr_freecap/Classes/PiBaseApi.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2005-2021 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use SJBR\SrFreecap\Validation\Validator\CaptchaValidator;
|
||||
use SJBR\SrFreecap\ViewHelpers\AudioViewHelper;
|
||||
use SJBR\SrFreecap\ViewHelpers\ImageViewHelper;
|
||||
use SJBR\SrFreecap\ViewHelpers\TranslateViewHelper;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
||||
|
||||
class PiBaseApi
|
||||
{
|
||||
/**
|
||||
* @var string The extension key
|
||||
*/
|
||||
public $extKey = 'sr_freecap';
|
||||
|
||||
/**
|
||||
* This function generates an array of markers used to render the captcha element
|
||||
*
|
||||
* @return array marker array containing the captcha markers to be sustituted in the html template
|
||||
*/
|
||||
public function makeCaptcha()
|
||||
{
|
||||
// Get the configuration manager
|
||||
$configurationManager = GeneralUtility::makeInstance(ConfigurationManagerInterface::class);
|
||||
|
||||
// Get translation view helper
|
||||
$translator = GeneralUtility::makeInstance(TranslateViewHelper::class);
|
||||
$translator->injectConfigurationManager($configurationManager);
|
||||
|
||||
$markerArray = [];
|
||||
$markerArray['###'. strtoupper($this->extKey) . '_NOTICE###'] = $translator->render('notice') . ' ' . $translator->render('explain');
|
||||
|
||||
// Get the captcha image view helper
|
||||
$imageViewHelper = GeneralUtility::makeInstance(ImageViewHelper::class);
|
||||
$imageViewHelper->injectConfigurationManager($configurationManager);
|
||||
$markerArray['###'. strtoupper($this->extKey) . '_IMAGE###'] = $imageViewHelper->render('pi1');
|
||||
$markerArray['###'. strtoupper($this->extKey) . '_CANT_READ###'] = '';
|
||||
|
||||
// Get the audio icon view helper
|
||||
$audioViewHelper = GeneralUtility::makeInstance(AudioViewHelper::class);
|
||||
$audioViewHelper->injectConfigurationManager($configurationManager);
|
||||
$markerArray['###'. strtoupper($this->extKey) . '_ACCESSIBLE###'] = $audioViewHelper->render('pi1');
|
||||
|
||||
return $markerArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the word that was entered against the hashed value
|
||||
*
|
||||
* @param string $word: hte word that was entered
|
||||
* @return bool true, if the word entered matches the hashes value
|
||||
*/
|
||||
public function checkWord($word)
|
||||
{
|
||||
// Get the validator
|
||||
$validator = GeneralUtility::makeInstance(CaptchaValidator::class);
|
||||
// Check word
|
||||
return !$validator->validate($word)->hasErrors();
|
||||
}
|
||||
}
|
||||
class_alias('SJBR\\SrFreecap\\PiBaseApi', 'tx_srfreecap_pi2');
|
||||
128
typo3conf/ext/sr_freecap/Classes/Utility/AudioContentUtility.php
Normal file
128
typo3conf/ext/sr_freecap/Classes/Utility/AudioContentUtility.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Utility;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2020 Stanislas Rolland <typo32020(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
/**
|
||||
* Utility dealing with audio content
|
||||
*/
|
||||
class AudioContentUtility
|
||||
{
|
||||
/**
|
||||
* Joins multiple audio files
|
||||
*
|
||||
* @param array $files: the array of audio files
|
||||
* @param string $format: the audio format
|
||||
* @return string the contents of joined audio file
|
||||
*/
|
||||
public static function joinAudioFiles($files, $format = 'wav') {
|
||||
switch ($format) {
|
||||
case 'mp3':
|
||||
return self::joinMp3Files($files);
|
||||
break;
|
||||
case 'wav':
|
||||
default:
|
||||
return self::joinWavFiles($files);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins multiple wav files
|
||||
*
|
||||
* All wave files need to have the same format and need to be uncompressed.
|
||||
* The headers of the last file will be used (with recalculated datasize
|
||||
* of course)
|
||||
*
|
||||
* @link http://ccrma.stanford.edu/CCRMA/Courses/422/projects/WaveFormat/
|
||||
* @link http://www.thescripts.com/forum/thread3770.html
|
||||
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
||||
* @author Andreas Gohr <gohr@cosmocode.de>
|
||||
*
|
||||
* @param array $wavs: the array of wav files
|
||||
* @return string the contents of joined wav file
|
||||
*/
|
||||
protected static function joinWavFiles($wavs)
|
||||
{
|
||||
$fields = join('/', array(
|
||||
'H8Format',
|
||||
'H8Subchunk1ID',
|
||||
'VSubchunk1Size',
|
||||
'vAudioFormat',
|
||||
'vNumChannels',
|
||||
'VSampleRate',
|
||||
'VByteRate',
|
||||
'vBlockAlign',
|
||||
'vBitsPerSample'
|
||||
));
|
||||
$data = '';
|
||||
foreach ($wavs as $wav){
|
||||
$fp = fopen($wav, 'rb');
|
||||
// Read ChunkID
|
||||
$headerPart1 = fread($fp, 4);
|
||||
// Read ChunkSize
|
||||
$headerPart2 = fread($fp, 4);
|
||||
// Read following fields
|
||||
$headerPart3 = fread($fp, 28);
|
||||
$info = unpack($fields, $headerPart3);
|
||||
// Read optional extra stuff
|
||||
// We will not use this since AudioFormat of all our sound files is PCM
|
||||
if ($info['Subchunk1Size'] > 16) {
|
||||
$headerPart3 .= fread($fp, ($info['Subchunk1Size']-16));
|
||||
}
|
||||
// Read SubChunk2ID
|
||||
$headerPart3 .= fread($fp, 4);
|
||||
// Read Subchunk2Size
|
||||
$size = unpack('VSubChunk2Size', fread($fp, 4));
|
||||
$size = $size['SubChunk2Size'];
|
||||
// Read data
|
||||
$data .= fread($fp, $size);
|
||||
fclose($fp);
|
||||
}
|
||||
return $headerPart1 . pack('V', 36 + strlen($data)) . $headerPart3 . pack('V', strlen($data)) . $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins multiple mp3 files
|
||||
*
|
||||
* All mp3 files need to have the same format and need to be uncompressed.
|
||||
* The headers of the last file will be used (with recalculated datasize
|
||||
* of course)
|
||||
*
|
||||
* @link http://www.theblog.ca/merge-mp3s-php
|
||||
* @param array $files: the array of mp3 files
|
||||
* @return string the contents of joined mp3 file
|
||||
*/
|
||||
protected static function joinMp3Files($files)
|
||||
{
|
||||
$data = '';
|
||||
foreach ($files as $file) {
|
||||
$mp3 = new Mp3ContentUtility($file);
|
||||
$data .= $mp3->striptags();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Utility;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2022 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
class EncryptionUtility
|
||||
{
|
||||
/**
|
||||
* Salt
|
||||
*/
|
||||
const SALT = 'cH!swe!retReGu7W6bEDRup7usuDUh9THeD2CHeGE*ewr4n39=E@rAsp7c-Ph@pH';
|
||||
|
||||
/**
|
||||
* Encrypts a string
|
||||
*
|
||||
* @param array $string: the string to be encrypted
|
||||
* @return array an array with the string as the first element and the initialization vector as the second element
|
||||
*/
|
||||
public static function encrypt($string)
|
||||
{
|
||||
if (in_array('openssl', get_loaded_extensions())) {
|
||||
$encryptionAlgorithm = strtolower($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['sr_freecap']['encryptionAlgorithm'] ?? 'aes-256-cbc');
|
||||
$availableAlgorithms = openssl_get_cipher_methods(true);
|
||||
if (in_array($encryptionAlgorithm, $availableAlgorithms)) {
|
||||
$key = md5($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] ?? 0, true);
|
||||
$iv_size = openssl_cipher_iv_length($encryptionAlgorithm);
|
||||
$salt = (isset($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['sr_freecap']['salt']) && trim($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['sr_freecap']['salt'])) ? trim($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['sr_freecap']['salt']) : self::SALT;
|
||||
$hash = hash('sha256', $salt . $key . $salt);
|
||||
$iv = substr($hash, strlen($hash) - $iv_size);
|
||||
$key = substr($hash, 0, 32);
|
||||
$string = openssl_encrypt($string, $encryptionAlgorithm, $key, OPENSSL_RAW_DATA, $iv);
|
||||
$cypher = [base64_encode($string), base64_encode($iv)];
|
||||
} else {
|
||||
$cypher = [base64_encode($string)];
|
||||
}
|
||||
} else {
|
||||
$cypher = [base64_encode($string)];
|
||||
}
|
||||
return $cypher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a string
|
||||
*
|
||||
* @param array $cypher: an array as returned by encrypt()
|
||||
* @return string the decrypted string
|
||||
*/
|
||||
public static function decrypt($cypher)
|
||||
{
|
||||
if (in_array('openssl', get_loaded_extensions())) {
|
||||
$encryptionAlgorithm = strtolower($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['sr_freecap']['encryptionAlgorithm'] ?? 'aes-256-cbc');
|
||||
$availableAlgorithms = openssl_get_cipher_methods(true);
|
||||
if (in_array($encryptionAlgorithm, $availableAlgorithms)) {
|
||||
$key = md5($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] ?? 0, true);
|
||||
$salt = isset($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['sr_freecap']['salt']) ? trim($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['sr_freecap']['salt']) : self::SALT;
|
||||
$hash = hash('sha256', $salt . $key . $salt);
|
||||
$key = substr($hash, 0, 32);
|
||||
$string = trim(openssl_decrypt(base64_decode($cypher[0]), $encryptionAlgorithm, $key, OPENSSL_RAW_DATA, base64_decode($cypher[1])));
|
||||
} else {
|
||||
$string = base64_decode($cypher[0]);
|
||||
}
|
||||
} else {
|
||||
$string = base64_decode($cypher[0]);
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
146
typo3conf/ext/sr_freecap/Classes/Utility/FontMakingUtility.php
Normal file
146
typo3conf/ext/sr_freecap/Classes/Utility/FontMakingUtility.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Utility;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2022 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Utility for making GD fonts
|
||||
*/
|
||||
class FontMakingUtility
|
||||
{
|
||||
/**
|
||||
* Returns an image displaying a list of characters with specified font file and character size
|
||||
*
|
||||
* @param string $characters: text to display on the image
|
||||
* @param string $font: specified True Type font file name
|
||||
* @param integer $width: width of each character
|
||||
* @param string $height: height of the image
|
||||
* @return array image file info array
|
||||
*/
|
||||
public static function makeFontImage($characters, $font, $width = 34, $height = 50)
|
||||
{
|
||||
$size = intval($height * .8);
|
||||
$vertOffset = intval($height * .7);
|
||||
$color = '#000000';
|
||||
$bgColor = 'white';
|
||||
$align = 'left';
|
||||
|
||||
$charactersArray = explode(',', $characters);
|
||||
$charactersCount = count($charactersArray);
|
||||
|
||||
$gifObjArray = array();
|
||||
$gifObjArray['backColor'] = $bgColor;
|
||||
$gifObjArray['transparentBackground'] = 0;
|
||||
$gifObjArray['reduceColors'] = '';
|
||||
$gifObjArray['maxWidth'] = ($charactersCount * $width) + 1;
|
||||
$gifObjArray['XY'] = ($charactersCount * $width) . ',' . $height;
|
||||
|
||||
for ($ic = 1; $ic < $charactersCount+1; $ic++) {
|
||||
$gifObjArray[$ic . '0'] = 'TEXT';
|
||||
$gifObjArray[$ic . '0.']['text'] = $charactersArray[$ic-1];
|
||||
$bbox = imagettfbbox($size, 0, GeneralUtility::getFileAbsFileName($font), $charactersArray[$ic-1]);
|
||||
$hOffset = intval(($width - ($bbox[4] - $bbox[6]))/2);
|
||||
$vOffset = intval(($width - ($bbox[7] - $bbox[1]))/2);
|
||||
|
||||
$gifObjArray[$ic . '0.']['niceText'] = 0;
|
||||
$gifObjArray[$ic . '0.']['antiAlias'] = 1;
|
||||
$gifObjArray[$ic . '0.']['align'] = $align;
|
||||
$gifObjArray[$ic . '0.']['fontSize'] = $size;
|
||||
$gifObjArray[$ic . '0.']['fontFile'] = '../' . $font;
|
||||
$gifObjArray[$ic . '0.']['fontColor'] = $color;
|
||||
$gifObjArray[$ic . '0.']['maxWidth'] = $width;
|
||||
$gifObjArray[$ic . '0.']['offset'] = (($ic-1) * $width + $hOffset) . ',' . $vertOffset;
|
||||
}
|
||||
$gifCreator = GeneralUtility::makeInstance(GifBuilderUtility::class);
|
||||
if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib'] ?? false) {
|
||||
$gifCreator->start($gifObjArray, []);
|
||||
return $gifCreator->gifBuild();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************\
|
||||
*
|
||||
* GD Fontmaker Copyright 2005 Howard Yeend
|
||||
* www.puremango.co.uk
|
||||
*
|
||||
* This file is part of GD Fontmaker.
|
||||
*
|
||||
* GD Fontmaker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GD Fontmaker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GD Fontmaker; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*
|
||||
\************************************************************/
|
||||
public static function makeFont($image, $numchars, $startchar, $pixelwidth, $pixelheight, $endianness = 0)
|
||||
{
|
||||
$startchar = ord($startchar);
|
||||
// encode this at start of font
|
||||
if ($endianness) {
|
||||
// big-endian
|
||||
$fontdata = chr(0).chr(0).chr(0).chr($numchars).chr(0).chr(0).chr(0).chr($startchar).chr(0).chr(0).chr(0).chr($pixelwidth).chr(0).chr(0).chr(0).chr($pixelheight);
|
||||
} else {
|
||||
// little-endian
|
||||
$fontdata = chr($numchars).chr(0).chr(0).chr(0).chr($startchar).chr(0).chr(0).chr(0).chr($pixelwidth).chr(0).chr(0).chr(0).chr($pixelheight).chr(0).chr(0).chr(0);
|
||||
}
|
||||
// loop through each pixel of each character of the PNG
|
||||
// (we know the dimensions of the characters because the user told us what they were)
|
||||
$y = 0;
|
||||
$x = 0;
|
||||
$start_x = 0;
|
||||
for ($c = 0; $c < $numchars*$pixelwidth; $c += $pixelwidth) {
|
||||
for ($y = 0; $y < $pixelheight; $y++) {
|
||||
for ($x = $c; $x < $c+$pixelwidth; $x++) {
|
||||
// get colour of this pixel
|
||||
$rgb = ImageColorAt($image, $x, $y);
|
||||
if ($rgb == 0) {
|
||||
// it's black; font data
|
||||
$fontdata .= chr(255);
|
||||
} else {
|
||||
// it's not black; background
|
||||
$fontdata .= chr(0);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $fontdata;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Utility;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2018 Stanislas Rolland <typo3(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
use TYPO3\CMS\Frontend\Imaging\GifBuilder;
|
||||
|
||||
/**
|
||||
* Utility extending Gif builder
|
||||
*/
|
||||
class GifBuilderUtility extends GifBuilder
|
||||
{
|
||||
/**
|
||||
* Returns the reference to a "resource" in TypoScript.
|
||||
*
|
||||
* @param string The resource value.
|
||||
* @return string Returns the relative filepath
|
||||
*/
|
||||
public function checkFile($file)
|
||||
{
|
||||
$file = GeneralUtility::getFileAbsFileName(Environment::getPublicPath() . '/' . $file);
|
||||
$file = PathUtility::stripPathSitePrefix($file);
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the input GDlib image pointer to file
|
||||
*
|
||||
* @param resource The GDlib image resource pointer
|
||||
* @param string The filename to write to
|
||||
* @param int $quality The image quality (for JPEGs)
|
||||
* @return mixed The output of either imageGif, imagePng or imageJpeg based on the filename to write
|
||||
* @see maskImageOntoImage(), scale(), output()
|
||||
*/
|
||||
public function ImageWrite($destImg, $theImage, $quality = 0)
|
||||
{
|
||||
return parent::ImageWrite($destImg, Environment::getPublicPath() . '/' . $theImage, $quality);
|
||||
}
|
||||
}
|
||||
446
typo3conf/ext/sr_freecap/Classes/Utility/ImageContentUtility.php
Normal file
446
typo3conf/ext/sr_freecap/Classes/Utility/ImageContentUtility.php
Normal file
@@ -0,0 +1,446 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Utility;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2022 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
/************************************************************\
|
||||
*
|
||||
* freeCap v1.4.1 Copyright 2005 Howard Yeend
|
||||
* www.puremango.co.uk
|
||||
*
|
||||
* This file is part of freeCap.
|
||||
*
|
||||
* freeCap is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* freeCap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with freeCap; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*
|
||||
\************************************************************/
|
||||
|
||||
use SJBR\SrFreecap\Utility\RandomContentUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Utility dealing with image content
|
||||
*/
|
||||
class ImageContentUtility {
|
||||
|
||||
const BACKGROUND_TYPE_TRANSPARENT = 'Transparent';
|
||||
const BACKGROUND_TYPE_WHITE_WITH_GRID = 'White with grid';
|
||||
const BACKGROUND_TYPE_WHITE_WITH_SQUIGGLES = 'White with squiggles';
|
||||
const BACKGROUND_TYPE_MORPHED_IMAGE_BLOCKS = 'Morphed image blocks';
|
||||
const MERGE_BACKGROUND_OVER_CAPTCHA = 0;
|
||||
const MERGE_CAPTCHA_OVER_BACKGROUND = 1;
|
||||
const TEXT_COLOR_UNIFORM = 0;
|
||||
const TEXT_COLOR_ONE_PER_CHARACTER = 1;
|
||||
const SITE_TAG_POSITION_TOP = 0;
|
||||
const SITE_TAG_POSITION_BOTTOM = 1;
|
||||
const SITE_TAG_POSITION_BOTH = 2;
|
||||
|
||||
/**
|
||||
* Write word on image
|
||||
*
|
||||
* @param int $width: width of the image in pixels
|
||||
* @param int $height: width of the image in pixels
|
||||
* @param string $word: the captcha word
|
||||
* @param int $textColorType (see constants)
|
||||
* @param array $textPosition: 'horizontal' => horizontal starting position of text, 'vertical' => vertical starting position of text
|
||||
* @param int $colorMaximum: 'darkness' => maximum color darkness along any dimension, 'lightness' => maximum color lightness along any dimension
|
||||
* @param string $backgroundType (see constants)
|
||||
* @param array $fontLocations: array of font files locations
|
||||
* @param array $fontWidths: array of font widths
|
||||
* @param int $morphfactor: text morphing factor
|
||||
* @return string GD image identifier of noisy background
|
||||
*/
|
||||
public static function writeWordOnImage($width, $height, $word, $textColorType, $textPosition, $colorMaximum, $backgroundType, $fontLocations, $fontWidths, $morphFactor = 1)
|
||||
{
|
||||
|
||||
$image = ImageCreate($width, $height);
|
||||
$image2 = ImageCreate($width, $height);
|
||||
// Set background colour (can change to any colour not in possible $text_col range)
|
||||
// it doesn't matter as it'll be transparent or coloured over.
|
||||
// if you're using background type 'Morphed image blocks', you might want to try to ensure that the color chosen
|
||||
// below doesn't appear too much in any of your background images.
|
||||
$background = ImageColorAllocate($image, 254, 254, 254);
|
||||
$background2 = ImageColorAllocate($image2, 254, 254, 254);
|
||||
// Set transparencies
|
||||
ImageColorTransparent($image, $background);
|
||||
// $image2 transparent to allow characters to overlap slightly while morphing
|
||||
ImageColorTransparent($image2, $background2);
|
||||
// Fill backgrounds
|
||||
ImageFill($image, 0, 0, $background);
|
||||
ImageFill($image2, 0, 0, $background2);
|
||||
|
||||
// Write word in random starting X position
|
||||
$word_start_x = RandomContentUtility::getRandomNumberInRange(5, $textPosition['horizontal']);
|
||||
// Y positions jiggled about later
|
||||
$word_start_y = $textPosition['vertical'];
|
||||
// Get uniform color
|
||||
if ($textColorType == self::TEXT_COLOR_UNIFORM) {
|
||||
$textColor = RandomContentUtility::getRandomColor($colorMaximum['darkness'], $colorMaximum['lightness'], $backgroundType == self::BACKGROUND_TYPE_MORPHED_IMAGE_BLOCKS);
|
||||
$textColor2 = ImageColorAllocate($image2, $textColor[0], $textColor[1], $textColor[2]);
|
||||
}
|
||||
// Write each character in different font
|
||||
$textFontWidths = array();
|
||||
$x_pos = $word_start_x;
|
||||
for ($i = 0; $i < strlen($word); $i++) {
|
||||
// Get changing color
|
||||
if ($textColorType == self::TEXT_COLOR_ONE_PER_CHARACTER) {
|
||||
$textColor = RandomContentUtility::getRandomColor($colorMaximum['darkness'], $colorMaximum['lightness'], $backgroundType == self::BACKGROUND_TYPE_MORPHED_IMAGE_BLOCKS);
|
||||
$textColor2 = ImageColorAllocate($image2, $textColor[0], $textColor[1], $textColor[2]);
|
||||
}
|
||||
$fontIndex = RandomContentUtility::getRandomNumberInRange(0, sizeof($fontLocations)-1);
|
||||
$font = ImageLoadFont($fontLocations[$fontIndex]);
|
||||
ImageString($image2, $font, $x_pos, $word_start_y, $word[$i], $textColor2);
|
||||
$textFontWidths[$i] = $fontWidths[$fontIndex];
|
||||
$x_pos += $textFontWidths[$i];
|
||||
}
|
||||
|
||||
// Morph Image
|
||||
// Firstly move each character up or down a bit:
|
||||
$x_pos = $word_start_x;
|
||||
$y_pos = 0;
|
||||
for ($i = 0; $i < strlen($word); $i++) {
|
||||
// Move on Y axis
|
||||
// Deviate at least 4 pixels between each letter
|
||||
$prev_y = $y_pos;
|
||||
do {
|
||||
$y_pos = RandomContentUtility::getRandomNumberInRange(-5, 5);
|
||||
} while ($y_pos < $prev_y + 2 && $y_pos > $prev_y - 2);
|
||||
ImageCopy($image, $image2, $x_pos, $y_pos, $x_pos, 0, $textFontWidths[$i], $height);
|
||||
$x_pos += $textFontWidths[$i];
|
||||
}
|
||||
ImageFilledRectangle($image2, 0, 0, $width, $height, $background2);
|
||||
|
||||
// Randomly morph each character individually on x-axis
|
||||
// This is where the main distortion happens
|
||||
$y_chunk = 1;
|
||||
$morph_x = 0;
|
||||
$orig_x = $word_start_x - $textFontWidths[0];
|
||||
for ($j = 0; $j < strlen($word); $j++) {
|
||||
$orig_x += $textFontWidths[$j];
|
||||
$y_pos = 0;
|
||||
for ($i = 0; $i <= $height; $i += $y_chunk) {
|
||||
// morph x += so that instead of deviating from orig x each time, we deviate from where we last deviated to
|
||||
// get it? instead of a zig zag, we get more of a sine wave.
|
||||
// I wish we could deviate more but it looks crap if we do.
|
||||
$morph_x += RandomContentUtility::getRandomNumberInRange(-$morphFactor, $morphFactor);
|
||||
// had to change this to ImageCopyMerge when starting using ImageCreateTrueColor
|
||||
// according to the manual; "when (pct is) 100 this function behaves identically to imagecopy()"
|
||||
// but this is NOT true when dealing with transparencies...
|
||||
ImageCopyMerge($image2, $image, $orig_x + $morph_x, $i + $y_pos, $orig_x, $i, $textFontWidths[$j], $y_chunk, 100);
|
||||
}
|
||||
}
|
||||
ImageFilledRectangle($image, 0, 0, $width, $height, $background);
|
||||
|
||||
// Now do the same on the y-axis
|
||||
// (much easier because we can just do it across the whole image, don't have to do it char-by-char)
|
||||
$y_pos = 0;
|
||||
$x_chunk = 1;
|
||||
for ($i = 0; $i <= $width ; $i += $x_chunk) {
|
||||
// Can result in image going too far off on Y-axis;
|
||||
// not much I can do about that, apart from make image bigger
|
||||
// again, I wish I could do 1.5 pixels
|
||||
$y_pos += RandomContentUtility::getRandomNumberInRange(-1, 1);
|
||||
ImageCopy($image, $image2, $i, $y_pos, $i, 0, $x_chunk, $height);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
ImageDestroy($image2);
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate noisy background
|
||||
*
|
||||
* @param int $width: width of the image in pixels
|
||||
* @param int $height: width of the image in pixels
|
||||
* @param string $word: the captcha word
|
||||
* @param string $backgroundType (see constants)
|
||||
* @param array $backgroundImages: array of background image file names
|
||||
* @param boolean $morphBackground: if TRUE, the background will be morphed
|
||||
* @param boolean $blurBackground: if TRUE, the background will be blurred
|
||||
* @return string GD image identifier of noisy background
|
||||
*/
|
||||
public static function generateNoisyBackground($width, $height, $word, $backgroundType, $backgroundImages = array(), $morphBackground = true, $blurBackground = true)
|
||||
{
|
||||
$image = ImageCreateTrueColor($width, $height);
|
||||
if ($backgroundType != self::BACKGROUND_TYPE_TRANSPARENT) {
|
||||
|
||||
// Generate noisy background, to be merged with CAPTCHA later
|
||||
// any suggestions on how best to do this much appreciated
|
||||
// sample code would be even better!
|
||||
// I'm not an OCR expert (hell, I'm not even an image expert; puremango.co.uk was designed in MsPaint)
|
||||
// so the noise models are based around my -guesswork- as to what would make it hard for an OCR prog
|
||||
// ideally, the character obfuscation would be strong enough not to need additional background noise
|
||||
// in any case, I hope at least one of the options given here provide some extra security!
|
||||
$tempBackground = ImageCreateTrueColor($width*1.5, $height*1.5);
|
||||
$background = ImageColorAllocate($image, 255, 255, 255);
|
||||
ImageFill($image, 0, 0, $background);
|
||||
$tempBackgroundColor = ImageColorAllocate($tempBackground, 255, 255, 255);
|
||||
ImageFill($tempBackground, 0, 0, $tempBackgroundColor);
|
||||
|
||||
// We draw all noise onto tempBackground
|
||||
// then if we're morphing, merge from tempBackground to image
|
||||
// or if not, just copy a $width x $height portion of $tempBackground to $image
|
||||
// tempBackground is much larger so that when morphing, the edges retain the noise.
|
||||
switch ($backgroundType) {
|
||||
case self::BACKGROUND_TYPE_WHITE_WITH_GRID:
|
||||
// Draw grid on x
|
||||
for ($i = RandomContentUtility::getRandomNumberInRange(6, 20); $i < $width*2; $i += RandomContentUtility::getRandomNumberInRange(10, 25)) {
|
||||
ImageSetThickness($tempBackground, RandomContentUtility::getRandomNumberInRange(2, 6));
|
||||
$textColor = RandomContentUtility::getRandomColor(100, 150);
|
||||
$textColor2 = ImageColorAllocate($tempBackground, $textColor[0], $textColor[1], $textColor[2]);
|
||||
ImageLine($tempBackground, $i, 0, $i, $height*2, $textColor2);
|
||||
}
|
||||
// Draw grid on y
|
||||
for ($i = RandomContentUtility::getRandomNumberInRange(6, 20); $i < $height*2 ; $i += RandomContentUtility::getRandomNumberInRange(10, 25)) {
|
||||
ImageSetThickness($tempBackground, RandomContentUtility::getRandomNumberInRange(2, 6));
|
||||
$textColor = RandomContentUtility::getRandomColor(100, 150);
|
||||
$textColor2 = ImageColorAllocate($tempBackground, $textColor[0], $textColor[1], $textColor[2]);
|
||||
ImageLine($tempBackground, 0, $i, $width*2, $i , $textColor2);
|
||||
}
|
||||
break;
|
||||
case self::BACKGROUND_TYPE_WHITE_WITH_SQUIGGLES:
|
||||
ImageSetThickness($tempBackground, 4);
|
||||
for ($i = 0; $i < strlen($word)+1; $i++) {
|
||||
$textColor = RandomContentUtility::getRandomColor(100, 150);
|
||||
$textColor2 = ImageColorAllocate($tempBackground, $textColor[0], $textColor[1], $textColor[2]);
|
||||
$points = Array();
|
||||
// Draw random squiggle for each character
|
||||
// the longer the loop, the more complex the squiggle
|
||||
// keep random so OCR can't say "if found shape has 10 points, ignore it"
|
||||
// each squiggle will, however, be a closed shape, so OCR could try to find
|
||||
// line terminations and start from there. (I don't think they're that advanced yet..)
|
||||
for ($j = 1; $j < RandomContentUtility::getRandomNumberInRange(5, 10); $j++) {
|
||||
$points[] = RandomContentUtility::getRandomNumberInRange(1*(20*($i+1)), 1*(50*($i+1)));
|
||||
$points[] = RandomContentUtility::getRandomNumberInRange(30, $height+30);
|
||||
}
|
||||
ImagePolygon($tempBackground, $points, intval(sizeof($points)/2), $textColor2);
|
||||
}
|
||||
break;
|
||||
case self::BACKGROUND_TYPE_MORPHED_IMAGE_BLOCKS:
|
||||
// Take random chunks of $backgroundImages and paste them onto the background
|
||||
for ($i = 0; $i < sizeof($backgroundImages); $i++) {
|
||||
// Read each image and its size
|
||||
$tempImages[$i] = ImageCreateFromJPEG(GeneralUtility::getFileAbsFileName($backgroundImages[$i]));
|
||||
$tempWidths[$i] = imagesx($tempImages[$i]);
|
||||
$tempHeights[$i] = imagesy($tempImages[$i]);
|
||||
}
|
||||
$blocksize = RandomContentUtility::getRandomNumberInRange(20, 60);
|
||||
for ($i = 0; $i < $width*2; $i += $blocksize) {
|
||||
// Could randomise blocksize here... hardly matters
|
||||
for ($j = 0; $j < $height*2; $j += $blocksize) {
|
||||
$imageIndex = RandomContentUtility::getRandomNumberInRange(0, sizeof($tempImages)-1);
|
||||
$cut_x = RandomContentUtility::getRandomNumberInRange(0, $tempWidths[$imageIndex]-$blocksize);
|
||||
$cut_y = RandomContentUtility::getRandomNumberInRange(0, $tempHeights[$imageIndex]-$blocksize);
|
||||
ImageCopy($tempBackground, $tempImages[$imageIndex], $i, $j, $cut_x, $cut_y, $blocksize, $blocksize);
|
||||
}
|
||||
}
|
||||
// Cleanup
|
||||
for ($i = 0; $i < sizeof($tempImages); $i++) {
|
||||
ImageDestroy($tempImages[$i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ($morphBackground) {
|
||||
// Morph background
|
||||
// We do this separately to the main text morph because:
|
||||
// a) the main text morph is done char-by-char, this is done across whole image
|
||||
// b) if an attacker could un-morph the background, it would un-morph the CAPTCHA
|
||||
// hence background is morphed differently to text
|
||||
// why do we morph it at all? it might make it harder for an attacker to remove the background
|
||||
// morph_chunk 1 looks better but takes longer
|
||||
// this is a different and less perfect morph than the one we do on the CAPTCHA
|
||||
// occasonally you get some dark background showing through around the edges
|
||||
// it doesn't need to be perfect as it's only the background.
|
||||
$morph_chunk = RandomContentUtility::getRandomNumberInRange(1, 5);
|
||||
$morph_y = 0;
|
||||
for ($x = 0; $x < $width; $x += $morph_chunk) {
|
||||
$morph_chunk = RandomContentUtility::getRandomNumberInRange(1, 5);
|
||||
$morph_y += RandomContentUtility::getRandomNumberInRange(-1, 1);
|
||||
ImageCopy($image, $tempBackground, $x, 0, $x+30, 30+$morph_y, $morph_chunk, $height*2);
|
||||
}
|
||||
|
||||
ImageCopy($tempBackground, $image, 0, 0, 0, 0, $width, $height);
|
||||
|
||||
$morph_x = 0;
|
||||
for ($y = 0; $y <= $height; $y += $morph_chunk) {
|
||||
$morph_chunk = RandomContentUtility::getRandomNumberInRange(1, 5);
|
||||
$morph_x += RandomContentUtility::getRandomNumberInRange(-1, 1);
|
||||
ImageCopy($image, $tempBackground, $morph_x, $y, 0, $y, $width, $morph_chunk);
|
||||
|
||||
}
|
||||
} else {
|
||||
// Just copy tempBackground onto $image
|
||||
ImageCopy($image, $tempBackground, 0, 0, 30, 30, $width, $height);
|
||||
}
|
||||
// Cleanup
|
||||
ImageDestroy($tempBackground);
|
||||
|
||||
if ($blurBackground) {
|
||||
$image = self::blurImage($image);
|
||||
}
|
||||
}
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge captcha image with background
|
||||
*
|
||||
* @param int $width: width of the image in pixels
|
||||
* @param int $height: width of the image in pixels
|
||||
* @param string $captchaImage: a GD image identifier
|
||||
* @param string $backgroundImage: a GD image identifier
|
||||
* @param string $backgroundType (see constants)
|
||||
* @param int $mergeType: 0 - Background over captcha, 1 - Captcha over background (see constants)
|
||||
* @param int $backgroundFadePercentage: fading factor for background
|
||||
* @return string GD image identifier of merged image
|
||||
*/
|
||||
public static function mergeCaptchaWithBackground($width, $height, $captchaImage, $backgroundImage, $backgroundType, $mergeType)
|
||||
{
|
||||
if ($backgroundType != self::BACKGROUND_TYPE_TRANSPARENT) {
|
||||
// How faded should the background be? (100=totally gone, 0=bright as the day)
|
||||
// to test how much protection the bg noise gives, take a screenshot of the freeCap image
|
||||
// and take it into a photo editor. play with contrast and brightness.
|
||||
// If you can remove most of the background, then it's not a good enough percentage
|
||||
switch ($backgroundType) {
|
||||
case self::BACKGROUND_TYPE_WHITE_WITH_GRID:
|
||||
case self::BACKGROUND_TYPE_WHITE_WITH_SQUIGGLES:
|
||||
$backgroundFadePercentage = 65;
|
||||
break;
|
||||
case self::BACKGROUND_TYPE_MORPHED_IMAGE_BLOCKS:
|
||||
$backgroundFadePercentage = 50;
|
||||
break;
|
||||
}
|
||||
// Slightly randomize the background fade
|
||||
$backgroundFadePercentage += RandomContentUtility::getRandomNumberInRange(-2, 2);
|
||||
// Fade background
|
||||
if ($backgroundType != self::BACKGROUND_TYPE_MORPHED_IMAGE_BLOCKS) {
|
||||
$tempImage = ImageCreateTrueColor($width, $height);
|
||||
$white = ImageColorAllocate($tempImage, 255, 255, 255);
|
||||
ImageFill($tempImage, 0, 0, $white);
|
||||
ImageCopyMerge($backgroundImage, $tempImage, 0, 0, 0, 0, $width, $height, $backgroundFadePercentage);
|
||||
ImageDestroy($tempImage);
|
||||
$colorFadePercentage = 50;
|
||||
} else {
|
||||
$colorFadePercentage = $backgroundFadePercentage;
|
||||
}
|
||||
// Merge background image with CAPTCHA image to create smooth background
|
||||
if ($mergeType == self::MERGE_CAPTCHA_OVER_BACKGROUND) {
|
||||
// Might want to not blur if using this method, otherwise leaves white-ish border around each letter
|
||||
ImageCopyMerge($backgroundImage, $captchaImage, 0, 0, 0, 0, $width, $height, 100);
|
||||
ImageCopy($captchaImage, $backgroundImage, 0, 0, 0, 0, $width, $height);
|
||||
} else {
|
||||
// Background over captcha
|
||||
ImageCopyMerge($captchaImage, $backgroundImage, 0, 0, 0, 0, $width, $height, $colorFadePercentage);
|
||||
}
|
||||
}
|
||||
return $captchaImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blurs an image
|
||||
*
|
||||
* @param string $image: a GD image identifier
|
||||
* @return string GD image identifier of blurred image
|
||||
*/
|
||||
public static function blurImage($image)
|
||||
{
|
||||
// w00t. my very own blur function
|
||||
// in GD2, there's a gaussian blur function. bunch of bloody show-offs... :-)
|
||||
|
||||
$width = imagesx($image);
|
||||
$height = imagesy($image);
|
||||
|
||||
$temp_im = ImageCreateTrueColor($width, $height);
|
||||
$bg = ImageColorAllocate($temp_im, 150, 150, 150);
|
||||
|
||||
// preserves transparency if in orig image
|
||||
ImageColorTransparent($temp_im, $bg);
|
||||
|
||||
// fill bg
|
||||
ImageFill($temp_im, 0, 0, $bg);
|
||||
|
||||
// anything higher than 3 makes it totally unreadable
|
||||
// might be useful in a 'real' blur function, though (ie blurring pictures not text)
|
||||
$distance = 1;
|
||||
// use $distance=30 to have multiple copies of the word. not sure if this is useful.
|
||||
|
||||
// blur by merging with itself at different x/y offsets:
|
||||
ImageCopyMerge($temp_im, $image, 0, 0, 0, $distance, $width, $height-$distance, 70);
|
||||
ImageCopyMerge($image, $temp_im, 0, 0, $distance, 0, $width-$distance, $height, 70);
|
||||
ImageCopyMerge($temp_im, $image, 0, $distance, 0, 0, $width, $height, 70);
|
||||
ImageCopyMerge($image, $temp_im, $distance, 0, 0, 0, $width, $height, 70);
|
||||
// remove temp image
|
||||
ImageDestroy($temp_im);
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the image with appropriate headers
|
||||
*
|
||||
* @param string $image: a GD image identifier
|
||||
* @param string $imageType: type of image (jpg, gif or png)
|
||||
* @return void
|
||||
*/
|
||||
public static function sendImage($image, $imageType)
|
||||
{
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
header('Pragma: no-cache');
|
||||
header('Cache-Control: no-cache, no-store, must-revalidate');
|
||||
// Setting privacy policy header for IE in popup window
|
||||
header('P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"');
|
||||
switch ($imageType) {
|
||||
case 'jpg':
|
||||
header('Content-Type: image/jpeg');
|
||||
ImageJPEG($image);
|
||||
break;
|
||||
case 'gif':
|
||||
header('Content-Type: image/gif');
|
||||
ImageGIF($image);
|
||||
break;
|
||||
case 'png':
|
||||
default:
|
||||
header('Content-Type: image/png');
|
||||
ImagePNG($image);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
159
typo3conf/ext/sr_freecap/Classes/Utility/LocalizationUtility.php
Normal file
159
typo3conf/ext/sr_freecap/Classes/Utility/LocalizationUtility.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Utility;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2009 Sebastian Kurfürst <sebastian@typo3.org>
|
||||
* (c) 2013-2021 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Http\ApplicationType;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Localization\Locales;
|
||||
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
|
||||
use TYPO3\CMS\Core\Site\SiteFinder;
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
/**
|
||||
* Localization helper which should be used to fetch appropriate words list or voice rendering language
|
||||
*
|
||||
*/
|
||||
class LocalizationUtility
|
||||
{
|
||||
/**
|
||||
* Key of the extension to which this class belongs
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $extensionKey = 'sr_freecap';
|
||||
|
||||
/**
|
||||
* Gets the location of the words list based on configured language
|
||||
*
|
||||
* @param string $defaultWordsList: location of the default words list
|
||||
* @return string the location of the words list to be used
|
||||
*/
|
||||
public static function getWordsListLocation($defaultWordsList = '')
|
||||
{
|
||||
$languageKeys = static::getLanguageKeys();
|
||||
$initialWordsList = $defaultWordsList;
|
||||
if (!trim($initialWordsList)) {
|
||||
$initialWordsList = 'EXT:' . self::$extensionKey . '/Resources/Private/Captcha/Words/default_freecap_words';
|
||||
}
|
||||
$path = dirname(GeneralUtility::getFileAbsFileName($initialWordsList)) . '/';
|
||||
$wordsListLocation = $path . $languageKeys['languageKey'] . '_freecap_words';
|
||||
if (!is_file($wordsListLocation)) {
|
||||
foreach ($languageKeys['alternativeLanguageKeys'] as $language) {
|
||||
$wordsListLocation = $path . $language . '_freecap_words';
|
||||
if (is_file($wordsListLocation)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!is_file($wordsListLocation)) {
|
||||
$wordsListLocation = $path . 'default_freecap_words';
|
||||
if (!is_file($wordsListLocation)) {
|
||||
$wordsListLocation = '';
|
||||
}
|
||||
}
|
||||
return $wordsListLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the directory of wav files based on configured language
|
||||
*
|
||||
* @return string name of the directory containing the wav files to be used
|
||||
*/
|
||||
public static function getVoicesDirectory()
|
||||
{
|
||||
$languageKeys = static::getLanguageKeys();
|
||||
$path = ExtensionManagementUtility::extPath(self::$extensionKey) . 'Resources/Private/Captcha/Voices/';
|
||||
$voicesDirectory = $path . $languageKeys['languageKey'] . '/';
|
||||
if (!is_dir($voicesDirectory)) {
|
||||
foreach ($languageKeys['alternativeLanguageKeys'] as $language) {
|
||||
$voicesDirectory = $path . $language . '/';
|
||||
if (is_dir($voicesDirectory)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!is_dir($voicesDirectory)) {
|
||||
$voicesDirectory = $path . 'default/';
|
||||
}
|
||||
return $voicesDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the currently active language/language_alt keys.
|
||||
* Default values are "default" for language key and an empty array for language_alt key.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function getLanguageKeys(): array
|
||||
{
|
||||
$languageKeys = [
|
||||
'languageKey' => 'default',
|
||||
'alternativeLanguageKeys' => [],
|
||||
];
|
||||
if (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
|
||||
&& ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend()
|
||||
) {
|
||||
$tsfe = static::getTypoScriptFrontendController();
|
||||
$pageId = $tsfe->id;
|
||||
$siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
|
||||
$currentSite = $siteFinder->getSiteByPageId($pageId);
|
||||
$languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
|
||||
// Current language
|
||||
$currentSiteLanguageId = $languageAspect->getId();
|
||||
$currentSiteLanguage = $currentSite->getLanguageById((int)$currentSiteLanguageId);
|
||||
$languageKeys['languageKey'] = $currentSiteLanguage->getTypo3Language();
|
||||
// Alternative languages
|
||||
$alternativeLanguageIds = $languageAspect->getFallbackChain();
|
||||
foreach ($alternativeLanguageIds as $alternativeLanguageId) {
|
||||
$alternativeLanguage = $currentSite->getLanguageById((int)$alternativeLanguageId);
|
||||
$languageKeys['alternativeLanguageKeys'][] = $alternativeLanguage->getTypo3Language();
|
||||
}
|
||||
if (empty($languageKeys['alternativeLanguageKeys'])) {
|
||||
$locales = GeneralUtility::makeInstance(Locales::class);
|
||||
if (in_array($languageKeys['languageKey'], $locales->getLocales())) {
|
||||
foreach ($locales->getLocaleDependencies($languageKeys['languageKey']) as $language) {
|
||||
$languageKeys['alternativeLanguageKeys'][] = $language;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$languageKeys['languageKey'] = $GLOBALS['BE_USER']->uc['lang'];
|
||||
}
|
||||
return $languageKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TypoScriptFrontendController
|
||||
*/
|
||||
protected static function getTypoScriptFrontendController()
|
||||
{
|
||||
return $GLOBALS['TSFE'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Utility;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2020 Stanislas Rolland <typo32020(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
/**
|
||||
* Utility dealing with mp3 audio content
|
||||
* See http://www.theblog.ca/merge-mp3s-php
|
||||
*/
|
||||
class Mp3ContentUtility
|
||||
{
|
||||
var $mp3Content;
|
||||
|
||||
// Create a new mp3
|
||||
public function __construct($file = '')
|
||||
{
|
||||
if ($file != '') {
|
||||
$this->mp3Content = file_get_contents($file);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the mp3 content
|
||||
public function getContent()
|
||||
{
|
||||
return $this->mp3Content;
|
||||
}
|
||||
|
||||
// Calculate where's the beginning of the sound file
|
||||
protected function getStart()
|
||||
{
|
||||
$strlen = strlen($this->mp3Content);
|
||||
for ($i=0; $i < $strlen; $i++) {
|
||||
$v = substr($this->mp3Content, $i, 1);
|
||||
$value = ord($v);
|
||||
if ($value == 255) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate where's the end of the sound file
|
||||
protected function getIdvEnd()
|
||||
{
|
||||
$strlen = strlen($this->mp3Content);
|
||||
$str = substr($this->mp3Content, ($strlen - 128));
|
||||
$str1 = substr($str, 0, 3);
|
||||
if (strtolower($str1) == strtolower('TAG')) {
|
||||
return $str;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the ID3 tags
|
||||
public function striptags()
|
||||
{
|
||||
// Remove start stuff...
|
||||
$newStr = '';
|
||||
$s = $start = $this->getStart();
|
||||
if ($s === false) {
|
||||
return false;
|
||||
} else {
|
||||
$this->mp3Content = substr($this->mp3Content, $start);
|
||||
}
|
||||
//Remove end tag stuff
|
||||
$end = $this->getIdvEnd();
|
||||
if ($end !== false) {
|
||||
$this->mp3Content = substr($this->mp3Content, 0, (strlen($this->mp3Content)-129));
|
||||
}
|
||||
return $this->mp3Content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Utility;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2020 Stanislas Rolland <typo32020(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
/**
|
||||
* Random content utility
|
||||
*/
|
||||
class RandomContentUtility
|
||||
{
|
||||
/**
|
||||
* Returns a random number within the given range
|
||||
*
|
||||
* @param int $min: the lower boundary of the range
|
||||
* @param int $max: the upper boundary of the range
|
||||
* @return int the generated number
|
||||
*/
|
||||
public static function getRandomNumberInRange($min, $max)
|
||||
{
|
||||
if ($min > $max) {
|
||||
$newMin = $max;
|
||||
$newMax = $min;
|
||||
} else {
|
||||
$newMin = $min;
|
||||
$newMax = $max;
|
||||
}
|
||||
return mt_rand($newMin, $newMax);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random color in a the form of an array of 3 numbers
|
||||
*
|
||||
* @param int $colorMaximumDarkness: maximum darkness along any dimension
|
||||
* @param int $colorMaximumLightness: maximum lightness along any dimension
|
||||
* @param boolean $darker: if true, produce a possibly darker image by default
|
||||
* @return array the random color
|
||||
*/
|
||||
public static function getRandomColor ($colorMaximumDarkness, $colorMaximumLightness, $darker = false)
|
||||
{
|
||||
$color = [];
|
||||
if ($darker) {
|
||||
// Needs darker colour..
|
||||
$minimum = isset($colorMaximumDarkness) ? $colorMaximumDarkness : 10;
|
||||
$maximum = isset($colorMaximumLightness) ? $colorMaximumLightness : 100;
|
||||
} else {
|
||||
$minimum = isset($colorMaximumDarkness) ? $colorMaximumDarkness : 30;
|
||||
$maximum = isset($colorMaximumLightness) ? $colorMaximumLightness : 140;
|
||||
}
|
||||
for ($i = 0; $i < 3 ; $i++) {
|
||||
$color[] = self::getRandomNumberInRange($minimum, $maximum);
|
||||
}
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random word
|
||||
*
|
||||
* @param boolean $useWordsList: if true, a word dictionary is used
|
||||
* @param string $wordsList: dictionary file location
|
||||
* @param boolean $numbersOnly: if true, use only numbers
|
||||
*
|
||||
* @return string random word
|
||||
*/
|
||||
public static function getRandomWord($useWordsList = false, $wordsList = '', $numbersOnly = false, $maxWordLength = 6)
|
||||
{
|
||||
if ($useWordsList && is_file($wordsList)) {
|
||||
// Load dictionary and choose random word
|
||||
// Keep dictionary in non-web accessible folder, or htaccess it
|
||||
// or modify so word comes from a database; SELECT word FROM words ORDER BY rand() LIMIT 1
|
||||
$words = @file($wordsList);
|
||||
$word = strtolower($words[self::getRandomNumberInRange(0, sizeof($words)-1)]);
|
||||
// Cut off line breaks
|
||||
$word = preg_replace('/['.preg_quote(chr(10).chr(13)).']+/', '', $word);
|
||||
unset($words);
|
||||
} else {
|
||||
// Based on code originally by breakzero at hotmail dot com
|
||||
// (http://uk.php.net/manual/en/function.rand.php)
|
||||
// generate pseudo-random string
|
||||
// doesn't use ijtf as are easily mistaken
|
||||
|
||||
// I'm not using numbers because the custom fonts I've created don't support anything other than
|
||||
// lowercase or space (but you can download new fonts or create your own using my GD fontmaker script)
|
||||
if ($numbersOnly) {
|
||||
$consonants = '123456789';
|
||||
$vowels = '123456789';
|
||||
} else {
|
||||
$consonants = 'bcdghklmnpqrsvwxyz';
|
||||
$vowels = 'aeuo';
|
||||
}
|
||||
$word = '';
|
||||
$wordlen = self::getRandomNumberInRange(5, $maxWordLength);
|
||||
for ($i = 0; $i < $wordlen; $i++) {
|
||||
// Don't allow to start with 'vowel'
|
||||
if (self::getRandomNumberInRange(0, 20) >= 10 && $i != 0) {
|
||||
$word .= $vowels[self::getRandomNumberInRange(0, strlen($vowels)-1)];
|
||||
} else {
|
||||
$word .= $consonants[self::getRandomNumberInRange(0, strlen($consonants)-1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $word;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Validation\Validator;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2021 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use SJBR\SrFreecap\Domain\Repository\WordRepository;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
|
||||
|
||||
/**
|
||||
* Captcha validator
|
||||
*/
|
||||
class CaptchaValidator extends AbstractValidator
|
||||
{
|
||||
/**
|
||||
* Specifies whether this validator accepts empty values.
|
||||
*
|
||||
* If this is true, the validators isValid() method is not called in case of an empty value
|
||||
* Note: A value is considered empty if it is null or an empty string!
|
||||
* By default all validators except for NotEmpty and the Composite Validators accept empty values
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $acceptsEmptyValues = false;
|
||||
|
||||
/**
|
||||
* @var string Name of the extension this controller belongs to
|
||||
*/
|
||||
protected $extensionName = 'SrFreecap';
|
||||
|
||||
/**
|
||||
* Check the word that was entered against the hashed value
|
||||
* Returns true, if the given property ($word) matches the session captcha value.
|
||||
*
|
||||
* @param string $word: the word that was entered and should be validated
|
||||
* @return boolean true, if the word entered matches the hash value, false if an error occured
|
||||
*/
|
||||
public function isValid($word)
|
||||
{
|
||||
$isValid = false;
|
||||
// This validator needs a frontend user session
|
||||
if (is_object($GLOBALS ['TSFE']) && isset($GLOBALS ['TSFE']->fe_user)) {
|
||||
// Get session data
|
||||
$wordRepository = GeneralUtility::makeInstance(WordRepository::class);
|
||||
$wordObject = $wordRepository->getWord();
|
||||
$wordHash = $wordObject->getWordHash();
|
||||
// Check the word hash against the stored hash value
|
||||
if (!empty($wordHash) && !empty($word)) {
|
||||
if ($wordObject->getHashFunction() == 'md5') {
|
||||
// All freeCap words are lowercase.
|
||||
// font #4 looks uppercase, but trust me, it's not...
|
||||
if (md5(strtolower(utf8_decode($word))) == $wordHash) {
|
||||
// Reset freeCap session vars
|
||||
// Cannot stress enough how important it is to do this
|
||||
// Defeats re-use of known image with spoofed session id
|
||||
$wordRepository->cleanUpWord();
|
||||
$isValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$isValid = empty($word);
|
||||
}
|
||||
if (!$isValid) {
|
||||
// Please enter the word or number as it appears in the image. The entered value was incorrect.
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'9221561048',
|
||||
'SrFreecap'
|
||||
),
|
||||
9221561048
|
||||
);
|
||||
}
|
||||
return $isValid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\Validation\Validator;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2018 Stanislas Rolland <typo3@sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
|
||||
|
||||
/**
|
||||
* Validator for True Type Font file existence
|
||||
*
|
||||
*/
|
||||
class TtfFileValidator extends AbstractValidator
|
||||
{
|
||||
/**
|
||||
* Returns true, if the given property ($propertyValue) is a valid number in the given range.
|
||||
*
|
||||
* If at least one error occurred, the result is false.
|
||||
*
|
||||
* @param mixed $value The value that should be validated
|
||||
* @return boolean true if the value is within the range, otherwise false
|
||||
*/
|
||||
protected function isValid($value)
|
||||
{
|
||||
$isValid = true;
|
||||
$absoluteFileName = GeneralUtility::getFileAbsFileName($value);
|
||||
// Check file existence
|
||||
if (!is_file($absoluteFileName)) {
|
||||
// A file with the given name could not be found.
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'9221561046',
|
||||
'SrFreecap'
|
||||
),
|
||||
9221561046
|
||||
);
|
||||
$isValid = false;
|
||||
} else {
|
||||
// Check file extension
|
||||
$pathInfo = pathinfo($absoluteFileName);
|
||||
if (strtolower($pathInfo['extension']) !== 'ttf') {
|
||||
// The specified file is not a True Type Font file.
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'9221561047',
|
||||
'SrFreecap'
|
||||
),
|
||||
9221561046
|
||||
);
|
||||
$isValid = false;
|
||||
}
|
||||
}
|
||||
return $isValid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\View\AudioPlayer;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2013-2022 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use SJBR\SrFreecap\Utility\AudioContentUtility;
|
||||
use SJBR\SrFreecap\Utility\EncryptionUtility;
|
||||
use SJBR\SrFreecap\Utility\LocalizationUtility;
|
||||
use TYPO3Fluid\Fluid\View\ViewInterface;
|
||||
|
||||
/**
|
||||
* Abstract class for rendering an audio version of the CAPTCHA
|
||||
*/
|
||||
class AbstractPlayFormat implements ViewInterface
|
||||
{
|
||||
/**
|
||||
* @var string Name of the extension this view helper belongs to
|
||||
*/
|
||||
protected $extensionName = 'SrFreecap';
|
||||
|
||||
/**
|
||||
* @var string Key of the extension this view helper belongs to
|
||||
*/
|
||||
protected $extensionKey = 'sr_freecap';
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Core\Domain\Model\Word
|
||||
*/
|
||||
protected $word;
|
||||
|
||||
/**
|
||||
* Add a variable to the view data collection.
|
||||
* Can be chained, so $this->view->assign(..., ...)->assign(..., ...); is possible
|
||||
*
|
||||
* @param string $key Key of variable
|
||||
* @param mixed $value Value of object
|
||||
* @return ViewInterface an instance of $this, to enable chaining
|
||||
*/
|
||||
public function assign($key, $value)
|
||||
{
|
||||
switch ($key) {
|
||||
case 'word':
|
||||
$this->word = $value;
|
||||
break;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple variables to the view data collection
|
||||
*
|
||||
* @param array $values array in the format array(key1 => value1, key2 => value2)
|
||||
* @return ViewInterface an instance of $this, to enable chaining
|
||||
*/
|
||||
public function assignMultiple(array $values)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the audio version of captcha
|
||||
*
|
||||
* @return string The audio output to play
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
// Get the catcha word
|
||||
$word = $this->getWord();
|
||||
// Get the letter rensering files
|
||||
$letterRenderingFiles = $this->getLetterRenderingFiles($word);
|
||||
// Join the files
|
||||
$audioContent = AudioContentUtility::joinAudioFiles($letterRenderingFiles);
|
||||
// Output proper headers and echo audio content
|
||||
$this->sendHeaders($audioContent);
|
||||
// Send audio content
|
||||
$this->sendAudioContent($audioContent);
|
||||
// Return the audio content
|
||||
return $audioContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the word that was stored in session data
|
||||
* @return string the retrieved and decoded word
|
||||
*/
|
||||
protected function getWord()
|
||||
{
|
||||
// Get cypher from session data
|
||||
$cypher = $this->word->getWordCypher();
|
||||
// Decrypt the word
|
||||
$decryptedString = EncryptionUtility::decrypt($cypher);
|
||||
return implode('-', preg_split('//', $decryptedString, -1, PREG_SPLIT_NO_EMPTY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an array of letter rendering files in the specified format
|
||||
*
|
||||
* @param string $word: the word to be spelled and played
|
||||
* @param string $extension: the audio file extension being used
|
||||
* @return array array of file names
|
||||
*/
|
||||
protected function getLetterRenderingFiles($word, $extension = 'wav')
|
||||
{
|
||||
$letterRenderingFiles = [];
|
||||
// Split the word
|
||||
$letters = preg_split('//', $word, -1, PREG_SPLIT_NO_EMPTY);
|
||||
// Get the directory containing the wav files
|
||||
$voicesDirectory = LocalizationUtility::getVoicesDirectory();
|
||||
// Assemble the file names
|
||||
foreach ($letters as $letter){
|
||||
// Word lists are encoded in ISO-8859-1 (possibly in ISO-8859-2?)
|
||||
$file = $voicesDirectory . ((isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) && $GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) ? utf8_encode($letter) : $letter) . '.' . $extension;
|
||||
if (is_file($file)) {
|
||||
$letterRenderingFiles[] = $file;
|
||||
}
|
||||
}
|
||||
return $letterRenderingFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends headers appropriate for audio content
|
||||
*
|
||||
* @param string $audioContent: the audio content that will be sent
|
||||
* @param string $mimeType: the audio mime type being used
|
||||
* @return void
|
||||
*/
|
||||
protected function sendHeaders($audioContent, $mimeType = 'x-wav')
|
||||
{
|
||||
header('Content-Type: audio/' . $mimeType);
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
header('Content-Length: ' . strlen($audioContent));
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
header('Pragma: no-cache');
|
||||
header('Cache-Control: no-cache, no-store, must-revalidate');
|
||||
// Setting privacy policy header for IE in popup window
|
||||
header('P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends audio content
|
||||
*
|
||||
* @param string $audioContent: the audio content that will be sent
|
||||
* @return void
|
||||
*/
|
||||
protected function sendAudioContent($audioContent)
|
||||
{
|
||||
echo $audioContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a given section.
|
||||
*
|
||||
* @param string $sectionName Name of section to render
|
||||
* @param array $variables The variables to use
|
||||
* @param boolean $ignoreUnknown Ignore an unknown section and just return an empty string
|
||||
* @return string rendered template for the section
|
||||
* @throws Exception\InvalidSectionException
|
||||
*/
|
||||
public function renderSection($sectionName, array $variables = [], $ignoreUnknown = false)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a partial.
|
||||
*
|
||||
* @param string $partialName
|
||||
* @param string $sectionName
|
||||
* @param array $variables
|
||||
* @param boolean $ignoreUnknown Ignore an unknown section and just return an empty string
|
||||
* @return string
|
||||
*/
|
||||
public function renderPartial($partialName, $sectionName, array $variables, $ignoreUnknown = false)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\View\AudioPlayer;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2013-2018 Stanislas Rolland <typo3(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use SJBR\SrFreecap\Utility\AudioContentUtility;
|
||||
|
||||
/**
|
||||
* Renders a mp3 audio version of the CAPTCHA
|
||||
*/
|
||||
class PlayMp3 extends AbstractPlayFormat
|
||||
{
|
||||
/**
|
||||
* Renders the audio version of captcha
|
||||
*
|
||||
* @return string The audio output to play
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
// Get the catcha word
|
||||
$word = $this->getWord();
|
||||
// Get the letter rensering files
|
||||
$letterRenderingFiles = $this->getLetterRenderingFiles($word, 'mp3');
|
||||
// Join the files
|
||||
$audioContent = AudioContentUtility::joinAudioFiles($letterRenderingFiles, 'mp3');
|
||||
// Output proper headers
|
||||
$this->sendHeaders($audioContent, 'mpeg');
|
||||
// Send audio content
|
||||
$this->sendAudioContent($audioContent);
|
||||
// Return the audio content
|
||||
return $audioContent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\View\AudioPlayer;
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012-2013 Stanislas Rolland <typo3(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
/**
|
||||
* Renders a wav audio version of the CAPTCHA
|
||||
*
|
||||
* @author Stanislas Rolland <typo3(arobas)sjbr.ca>
|
||||
*/
|
||||
class PlayWav extends AbstractPlayFormat {
|
||||
}
|
||||
264
typo3conf/ext/sr_freecap/Classes/View/ImageGenerator/ShowPng.php
Normal file
264
typo3conf/ext/sr_freecap/Classes/View/ImageGenerator/ShowPng.php
Normal file
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\View\ImageGenerator;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2005-2022 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
/*
|
||||
* Integrates freeCap v1.4.1 into TYPO3 and generates the freeCap CAPTCHA image.
|
||||
*/
|
||||
/*
|
||||
*
|
||||
* freeCap v1.4.1 Copyright 2005 Howard Yeend
|
||||
* www.puremango.co.uk
|
||||
*
|
||||
* This file is part of freeCap.
|
||||
*
|
||||
* freeCap is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* freeCap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with freeCap; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
use SJBR\SrFreecap\Domain\Model\Word;
|
||||
use SJBR\SrFreecap\Domain\Repository\WordRepository;
|
||||
use SJBR\SrFreecap\Utility\EncryptionUtility;
|
||||
use SJBR\SrFreecap\Utility\ImageContentUtility;
|
||||
use SJBR\SrFreecap\Utility\RandomContentUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
use TYPO3Fluid\Fluid\View\ViewInterface;
|
||||
|
||||
/**
|
||||
* Renders a png image of the CAPTCHA
|
||||
*/
|
||||
class ShowPng implements ViewInterface
|
||||
{
|
||||
/**
|
||||
* @var string Name of the extension this view helper belongs to
|
||||
*/
|
||||
protected $extensionName = 'SrFreecap';
|
||||
|
||||
/**
|
||||
* @var string Name of the plugin this view helper belongs to
|
||||
*/
|
||||
protected $pluginName = 'ImageGenerator';
|
||||
|
||||
/**
|
||||
* @var string Key of the extension this view helper belongs to
|
||||
*/
|
||||
protected $extensionKey = 'sr_freecap';
|
||||
|
||||
/**
|
||||
* @var Word
|
||||
*/
|
||||
protected $word;
|
||||
|
||||
/**
|
||||
* @var array Configuration of this view
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* Add a variable to the view data collection.
|
||||
* Can be chained, so $this->view->assign(..., ...)->assign(..., ...); is possible
|
||||
*
|
||||
* @param string $key Key of variable
|
||||
* @param mixed $value Value of object
|
||||
* @return SJBR\SrFreecap\View\ImageGenerator\ShowPng an instance of $this, to enable chaining
|
||||
* @api
|
||||
*/
|
||||
public function assign($key, $value)
|
||||
{
|
||||
switch ($key) {
|
||||
case 'word':
|
||||
$this->word = $value;
|
||||
break;
|
||||
case 'settings':
|
||||
$this->settings = $value;
|
||||
break;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple variables to the view data collection
|
||||
*
|
||||
* @param array $values array in the format array(key1 => value1, key2 => value2)
|
||||
* @return SJBR\SrFreecap\View\ImageGenerator\ShowPng an instance of $this, to enable chaining
|
||||
* @api
|
||||
*/
|
||||
public function assignMultiple(array $values)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the captcha image
|
||||
*
|
||||
* @return string empty string (the image is sent here)
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
// Avoid Brute Force Attacks:
|
||||
if (!$this->word->getAttempts()) {
|
||||
$this->word->setAttempts(1);
|
||||
} else {
|
||||
$this->word->setAttempts($this->word->getAttempts() + 1);
|
||||
// if more than ($this->settings['maxAttempts']) refreshes, block further refreshes
|
||||
// can be negated by connecting with new session id
|
||||
// could get round this by storing num attempts in database against IP
|
||||
// could get round that by connecting with different IP (eg, using proxy servers)
|
||||
// in short, there's little point trying to avoid brute forcing
|
||||
// the best way to protect against BF attacks is to ensure the dictionary is not
|
||||
// accessible via the web or use random string option
|
||||
if ($this->word->getAttempts() > $this->settings['maxAttempts']) {
|
||||
$this->word->setWordHash('');
|
||||
$this->word->setWordCypher([]);
|
||||
$this->word->setHashFunction('');
|
||||
// Get an instance of the word repository
|
||||
$wordRepository = GeneralUtility::makeInstance(WordRepository::class);
|
||||
// Reset the word
|
||||
$wordRepository->setWord($this->word);
|
||||
$string = LocalizationUtility::translate('max_attempts', $this->extensionName);
|
||||
$font = 5;
|
||||
$width = imagefontwidth($font) * strlen($string);
|
||||
$height = imagefontheight($font);
|
||||
$image = ImageCreate($width+2, $height+20);
|
||||
$background = ImageColorAllocate($image, 255,255,255);
|
||||
ImageColorTransparent($image, $background);
|
||||
$red = ImageColorAllocate($image, 255, 0, 0);
|
||||
ImageString($image, $font, 1, 10, $string, $red);
|
||||
ImageContentUtility::sendImage($image, $this->settings['imageFormat']);
|
||||
ImageDestroy($image);
|
||||
// Return an empty string
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// Get random word
|
||||
$word = RandomContentUtility::getRandomWord($this->settings['useWordsList'], $this->settings['wordsListLocation'], $this->settings['generateNumbers'] ?? 0, $this->settings['maxWordLength']);
|
||||
|
||||
// Save hash of word for comparison
|
||||
// using hash so that if there's an insecurity elsewhere (eg on the form processor),
|
||||
// an attacker could only get the hash
|
||||
// also, shared servers usually give all users access to the session files
|
||||
// echo `ls /tmp`; and echo `more /tmp/someone_elses_session_file`; usually work
|
||||
// so even if your site is 100% secure, someone else's site on your server might not be
|
||||
// hence, even if attackers can read the session file, they can't get the freeCap word
|
||||
// (though most hashes are easy to brute force for simple strings)
|
||||
$this->word->setWordHash(md5($word));
|
||||
|
||||
// We use a simple encrypt to prevent the session from being exposed
|
||||
if ($this->settings['accessibleOutput'] ?? false) {
|
||||
$this->word->setWordCypher(EncryptionUtility::encrypt($word));
|
||||
}
|
||||
|
||||
// Build the image
|
||||
$image = $this->buildImage($word, $this->settings['imageWidth'], $this->settings['imageHeight'], $this->settings['backgroundType']);
|
||||
|
||||
// Send the image
|
||||
ImageContentUtility::sendImage($image, $this->settings['imageFormat']);
|
||||
|
||||
// Cleanup
|
||||
ImageDestroy($image);
|
||||
|
||||
// Return an empty string
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the CAPTCHA image
|
||||
*
|
||||
* @param string $word
|
||||
* @return string GD image identifier of image
|
||||
*/
|
||||
protected function buildImage($word, $width, $height, $backgroundType)
|
||||
{
|
||||
$image = ImageCreate($width, $height);
|
||||
$background = ImageColorAllocate($image, 254, 254, 254);
|
||||
|
||||
// Write word on image
|
||||
$image = ImageContentUtility::writeWordOnImage($width, $height, $word, $this->settings['textColor'], $this->settings['textPosition'], $this->settings['colorMaximum'], $backgroundType, $this->settings['fontLocations'], $this->settings['fontWidths'], $this->settings['morphFactor']);
|
||||
|
||||
// Blur edges
|
||||
// Doesn't really add any security, but looks a lot nicer, and renders text a little easier to read
|
||||
// for humans (hopefully not for OCRs, but if you know better, feel free to disable this function)
|
||||
// (and if you do, let me know why)
|
||||
$image = ImageContentUtility::blurImage($image);
|
||||
|
||||
if ($this->settings['imageFormat'] != 'jpg' && $backgroundType == ImageContentUtility::BACKGROUND_TYPE_TRANSPARENT) {
|
||||
// Make background transparent
|
||||
ImageColorTransparent($image, $background);
|
||||
}
|
||||
|
||||
if ($backgroundType != ImageContentUtility::BACKGROUND_TYPE_TRANSPARENT) {
|
||||
// Get noisy background
|
||||
$image3 = ImageContentUtility::generateNoisyBackground($width, $height, $word, $backgroundType, $this->settings['backgroundImages'], $this->settings['backgroundMorph'], $this->settings['backgroundBlur']);
|
||||
// Merge with obfuscated background
|
||||
$image = ImageContentUtility::mergeCaptchaWithBackground($width, $height, $image, $image3, $backgroundType, $this->settings['mergeWithBackground']);
|
||||
ImageDestroy($image3);
|
||||
}
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a given section.
|
||||
*
|
||||
* @param string $sectionName Name of section to render
|
||||
* @param array $variables The variables to use
|
||||
* @param boolean $ignoreUnknown Ignore an unknown section and just return an empty string
|
||||
* @return string rendered template for the section
|
||||
* @throws Exception\InvalidSectionException
|
||||
*/
|
||||
public function renderSection($sectionName, array $variables = [], $ignoreUnknown = false)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a partial.
|
||||
*
|
||||
* @param string $partialName
|
||||
* @param string $sectionName
|
||||
* @param array $variables
|
||||
* @param boolean $ignoreUnknown Ignore an unknown section and just return an empty string
|
||||
* @return string
|
||||
*/
|
||||
public function renderPartial($partialName, $sectionName, array $variables, $ignoreUnknown = false)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
154
typo3conf/ext/sr_freecap/Classes/ViewHelpers/AudioViewHelper.php
Normal file
154
typo3conf/ext/sr_freecap/Classes/ViewHelpers/AudioViewHelper.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\ViewHelpers;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2013-2022 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use SJBR\SrFreecap\ViewHelpers\TranslateViewHelper;
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Session\Backend\Exception\SessionNotFoundException;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
|
||||
|
||||
class AudioViewHelper extends AbstractTagBasedViewHelper
|
||||
{
|
||||
/**
|
||||
* @var string Name of the extension this view helper belongs to
|
||||
*/
|
||||
protected $extensionName = 'SrFreecap';
|
||||
|
||||
/**
|
||||
* @var string Name of the extension this view helper belongs to
|
||||
*/
|
||||
protected $pluginName = 'tx_srfreecap';
|
||||
|
||||
/**
|
||||
* @var ConfigurationManagerInterface
|
||||
*/
|
||||
protected $configurationManager;
|
||||
|
||||
/**
|
||||
* @param ConfigurationManagerInterface $configurationManager
|
||||
* @return void
|
||||
*/
|
||||
public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager)
|
||||
{
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Context
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* @param Context $context
|
||||
*/
|
||||
public function injectContext(Context $context)
|
||||
{
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('suffix', 'string', 'Suffix to be appended to the extenstion key when forming css class names', false, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the captcha audio rendering request icon
|
||||
*
|
||||
* @param string suffix to be appended to the extenstion key when forming css class names
|
||||
* @return string The html used to render the captcha audio rendering request icon
|
||||
*/
|
||||
public function render($suffix = '')
|
||||
{
|
||||
// This viewhelper needs a frontend user session
|
||||
if (!is_object($this->getTypoScriptFrontendController()) || !isset($this->getTypoScriptFrontendController()->fe_user)) {
|
||||
throw new SessionNotFoundException('No frontend user found in session!');
|
||||
}
|
||||
$value = '';
|
||||
// Get the plugin configuration
|
||||
$settings = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, $this->extensionName, $this->pluginName);
|
||||
// Get the translation view helper
|
||||
$translator = GeneralUtility::makeInstance(TranslateViewHelper::class);
|
||||
// Generate the icon
|
||||
if (($settings['accessibleOutput'] ?? false) && ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem'] ?? false)) {
|
||||
$languageAspect = $this->context->getAspect('language');
|
||||
$fakeId = substr(md5(uniqid(rand())), 0, 5);
|
||||
$siteURL = GeneralUtility::getIndpEnv('TYPO3_SITE_URL');
|
||||
$urlParams = [
|
||||
'eIDSR' => 'sr_freecap_EidDispatcher',
|
||||
'id' => $GLOBALS['TSFE']->id,
|
||||
'pluginName' => 'AudioPlayer',
|
||||
'actionName' => 'play',
|
||||
'formatName' => 'wav',
|
||||
'L' => $languageAspect->getId()
|
||||
];
|
||||
if ($this->getTypoScriptFrontendController()->MP) {
|
||||
$urlParams['MP'] = $this->getTypoScriptFrontendController()->MP;
|
||||
}
|
||||
$audioURL = $siteURL . 'index.php?' . ltrim(GeneralUtility::implodeArrayForUrl('', $urlParams), '&');
|
||||
if (isset($settings['accessibleOutputImage']) && $settings['accessibleOutputImage']) {
|
||||
$value = '<input type="image" alt="' . $translator->render('click_here_accessible') . '"'
|
||||
. ' title="' . $translator->render('click_here_accessible') . '"'
|
||||
. ' src="' . $siteURL . PathUtility::stripPathSitePrefix(GeneralUtility::getFileAbsFileName($settings['accessibleOutputImage'])) . '"'
|
||||
. ' onclick="' . $this->extensionName . '.playCaptcha(\'' . $fakeId . '\', \'' . $audioURL . '\', \'' . $translator->render('noPlayMessage') . '\');return false;" style="cursor: pointer;"'
|
||||
. $this->getClassAttribute('image-accessible', $suffix) . ' />';
|
||||
} else {
|
||||
$value = '<span id="tx_srfreecap_captcha_playLink_' . $fakeId . '"'
|
||||
. $this->getClassAttribute('accessible-link', $suffix) . '>' . $translator->render('click_here_accessible_before_link')
|
||||
. '<a href="#" onClick="' . $this->extensionName . '.playCaptcha(\'' . $fakeId.'\', \'' . $audioURL . '\', \'' . $translator->render('noPlayMessage') . '\');return false;" style="cursor: pointer;" title="' . $translator->render('click_here_accessible') . '">'
|
||||
. $translator->render('click_here_accessible_link') . '</a>'
|
||||
. $translator->render('click_here_accessible_after_link') . '</span>';
|
||||
}
|
||||
$value .= '<span' . $this->getClassAttribute('accessible', $suffix) . ' id="tx_srfreecap_captcha_playAudio_' . $fakeId . '"></span>';
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a class attribute with a class-name prefixed with $this->pluginName and with all underscores substituted to dashes (-)
|
||||
*
|
||||
* @param string $class The class name (or the END of it since it will be prefixed by $this->pluginName.'-')
|
||||
* @param string suffix to be appended to the extenstion key when forming css class names
|
||||
* @return string the class attribute with the combined class name (with the correct prefix)
|
||||
*/
|
||||
protected function getClassAttribute ($class, $suffix = '')
|
||||
{
|
||||
return ' class="' . trim(str_replace('_', '-', $this->pluginName) . ($suffix ? '-' . $suffix . '-' : '-') . $class) . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TypoScriptFrontendController
|
||||
*/
|
||||
protected function getTypoScriptFrontendController()
|
||||
{
|
||||
return $GLOBALS['TSFE'];
|
||||
}
|
||||
}
|
||||
174
typo3conf/ext/sr_freecap/Classes/ViewHelpers/ImageViewHelper.php
Normal file
174
typo3conf/ext/sr_freecap/Classes/ViewHelpers/ImageViewHelper.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\ViewHelpers;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2013-2021 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use SJBR\SrFreecap\ViewHelpers\TranslateViewHelper;
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Page\PageRenderer;
|
||||
use TYPO3\CMS\Core\Session\Backend\Exception\SessionNotFoundException;
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
|
||||
|
||||
class ImageViewHelper extends AbstractTagBasedViewHelper
|
||||
{
|
||||
/**
|
||||
* @var string Name of the extension this view helper belongs to
|
||||
*/
|
||||
protected $extensionName = 'SrFreecap';
|
||||
|
||||
/**
|
||||
* @var string Name of the extension this view helper belongs to
|
||||
*/
|
||||
protected $extensionKey = 'sr_freecap';
|
||||
|
||||
/**
|
||||
* @var string Name of the plugin this view helper belongs to
|
||||
*/
|
||||
protected $pluginName = 'tx_srfreecap';
|
||||
|
||||
/**
|
||||
* @var ConfigurationManagerInterface
|
||||
*/
|
||||
protected $configurationManager;
|
||||
|
||||
/**
|
||||
* @param ConfigurationManagerInterface $configurationManager
|
||||
*/
|
||||
public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager)
|
||||
{
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var PageRenderer
|
||||
*/
|
||||
protected $pageRenderer;
|
||||
|
||||
/**
|
||||
* @param PageRenderer $pageRenderer
|
||||
*/
|
||||
public function injectPageRenderer(PageRenderer $pageRenderer)
|
||||
{
|
||||
$this->pageRenderer = $pageRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Context
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* @param Context $context
|
||||
*/
|
||||
public function injectContext(Context $context)
|
||||
{
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('suffix', 'string', 'Suffix to be appended to the extenstion key when forming css class names', false, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the captcha image html
|
||||
*
|
||||
* @param string suffix to be appended to the extenstion key when forming css class names
|
||||
* @return string The html used to render the captcha image
|
||||
*/
|
||||
public function render($suffix = '')
|
||||
{
|
||||
// This viewhelper needs a frontend user session
|
||||
if (!is_object($this->getTypoScriptFrontendController()) || !isset($this->getTypoScriptFrontendController()->fe_user)) {
|
||||
throw new SessionNotFoundException('No frontend user found in session!');
|
||||
}
|
||||
|
||||
$value = '';
|
||||
|
||||
// Include the required JavaScript
|
||||
$this->pageRenderer->addJsFooterFile(PathUtility::stripPathSitePrefix(ExtensionManagementUtility::extPath($this->extensionKey)) . 'Resources/Public/JavaScript/freeCap.js');
|
||||
|
||||
// Disable caching
|
||||
$this->getTypoScriptFrontendController()->no_cache = true;
|
||||
|
||||
// Get the translation view helper
|
||||
$translator = GeneralUtility::makeInstance(TranslateViewHelper::class);
|
||||
|
||||
// Generate the image url
|
||||
$fakeId = substr(md5(uniqid(rand())), 0, 5);
|
||||
$siteURL = GeneralUtility::getIndpEnv('TYPO3_SITE_URL');
|
||||
$languageAspect = $this->context->getAspect('language');
|
||||
$urlParams = [
|
||||
'eIDSR' => 'sr_freecap_EidDispatcher',
|
||||
'id' => $this->getTypoScriptFrontendController()->id,
|
||||
'pluginName' => 'ImageGenerator',
|
||||
'actionName' => 'show',
|
||||
'formatName' => 'png',
|
||||
'L' => $languageAspect->getId()
|
||||
];
|
||||
if ($this->getTypoScriptFrontendController()->MP) {
|
||||
$urlParams['MP'] = $this->getTypoScriptFrontendController()->MP;
|
||||
}
|
||||
$urlParams['set'] = $fakeId;
|
||||
$imageUrl = $siteURL . 'index.php?' . ltrim(GeneralUtility::implodeArrayForUrl('', $urlParams), '&');
|
||||
|
||||
// Generate the html text
|
||||
$value = '<img' . $this->getClassAttribute('image', $suffix) . ' id="tx_srfreecap_captcha_image_' . $fakeId . '"'
|
||||
. ' src="' . htmlspecialchars($imageUrl) . '"'
|
||||
. ' alt="' . $translator->render('altText') . ' "/>'
|
||||
. '<span' . $this->getClassAttribute('cant-read', $suffix) . '>' . $translator->render('cant_read1')
|
||||
. ' <a href="#" onclick="this.blur();' . $this->extensionName . '.newImage(\'' . $fakeId . '\', \'' . $translator->render('noImageMessage').'\');return false;">'
|
||||
. $translator->render('click_here') . '</a>'
|
||||
. $translator->render('cant_read2') . '</span>';
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a class attribute with a class-name prefixed with $this->pluginName and with all underscores substituted to dashes (-)
|
||||
*
|
||||
* @param string $class The class name (or the END of it since it will be prefixed by $this->pluginName.'-')
|
||||
* @param string suffix to be appended to the extenstion key when forming css class names
|
||||
* @return string the class attribute with the combined class name (with the correct prefix)
|
||||
*/
|
||||
protected function getClassAttribute($class, $suffix = '')
|
||||
{
|
||||
return ' class="' . trim(str_replace('_', '-', $this->pluginName) . ($suffix ? '-' . $suffix . '-' : '-') . $class) . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TypoScriptFrontendController
|
||||
*/
|
||||
protected function getTypoScriptFrontendController()
|
||||
{
|
||||
return $GLOBALS['TSFE'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
namespace SJBR\SrFreecap\ViewHelpers;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2013-2022 Stanislas Rolland <typo3AAAA@sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||||
*
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
|
||||
/**
|
||||
* Translate a key from locallang. The files are loaded from the folder
|
||||
* "Resources/Private/Language/".
|
||||
*
|
||||
* Handle salutation suffixes
|
||||
*
|
||||
* == Examples ==
|
||||
*
|
||||
* <code title="Translate key">
|
||||
* <f:translate key="key1" />
|
||||
* </code>
|
||||
* <output>
|
||||
* // value of key "key1" in the current website language
|
||||
* </output>
|
||||
*
|
||||
* <code title="Keep HTML tags">
|
||||
* <f:translate key="htmlKey" htmlEscape="false" />
|
||||
* </code>
|
||||
* <output>
|
||||
* // value of key "htmlKey" in the current website language, no htmlspecialchars applied
|
||||
* </output>
|
||||
*
|
||||
* <code title="Translate key from custom locallang file">
|
||||
* <f:translate key="LLL:EXT:myext/Resources/Private/Language/locallang.xml:key1" />
|
||||
* </code>
|
||||
* <output>
|
||||
* // value of key "key1" in the current website language
|
||||
* </output>
|
||||
*
|
||||
* <code title="Inline notation with arguments and default value">
|
||||
* {f:translate(key: 'argumentsKey', arguments: {0: 'dog', 1: 'fox'}, default: 'default value')}
|
||||
* </code>
|
||||
* <output>
|
||||
* // value of key "argumentsKey" in the current website language
|
||||
* // with "%1" and "%2" are replaced by "dog" and "fox" (printf)
|
||||
* // if the key is not found, the output is "default value"
|
||||
* </output>
|
||||
*/
|
||||
class TranslateViewHelper extends AbstractViewHelper
|
||||
{
|
||||
/**
|
||||
* @var string Name of the extension this view helper belongs to
|
||||
*/
|
||||
protected $extensionName = 'SrFreecap';
|
||||
|
||||
/**
|
||||
* @var string Name of the extension this view helper belongs to
|
||||
*/
|
||||
protected $pluginName = 'tx_srfreecap';
|
||||
|
||||
/**
|
||||
* @var array List of allowed suffixes
|
||||
*/
|
||||
protected $allowedSuffixes = ['formal', 'informal'];
|
||||
|
||||
/**
|
||||
* @var ConfigurationManagerInterface
|
||||
*/
|
||||
protected $configurationManager;
|
||||
|
||||
/**
|
||||
* @param ConfigurationManagerInterface $configurationManager
|
||||
* @return void
|
||||
*/
|
||||
public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager)
|
||||
{
|
||||
$this->configurationManager = $configurationManager;
|
||||
}
|
||||
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('key', 'string', 'The language key to translate', true);
|
||||
$this->registerArgument('default', 'string', 'Value to be used when the key is not found');
|
||||
$this->registerArgument('htmlEscape', 'boolean', 'Whether to escape html', false, true);
|
||||
$this->registerArgument('arguments', 'array', 'Arguments to be replaced in the string');
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a given key or use the tag body as default.
|
||||
*
|
||||
* @param string $key The locallang key
|
||||
* @param string $default if the given locallang key could not be found, this value is used. . If this argument is not set, child nodes will be used to render the default
|
||||
* @param boolean $htmlEscape true if the result should be htmlescaped. This won't have an effect for the default value
|
||||
* @param array $arguments Arguments to be replaced in the resulting string
|
||||
* @return string The translated key or tag body if key doesn't exist
|
||||
* @author Christopher Hlubek <hlubek@networkteam.com>
|
||||
* @author Bastian Waidelich <bastian@typo3.org>
|
||||
*/
|
||||
public function render($key = null)
|
||||
{
|
||||
if ($this->hasArgument('key')) {
|
||||
$key = $this->arguments['key'];
|
||||
}
|
||||
$value = null;
|
||||
$default = $this->hasArgument('default') ? $this->arguments['default'] : '';
|
||||
$htmlEscape = $this->hasArgument('htmlEscape') ? $this->arguments['htmlEscape'] : false;
|
||||
$arguments = $this->hasArgument('arguments') ? $this->arguments['arguments'] : [];
|
||||
// If the suffix is allowed and we have a localized string for the desired salutation, we'll take that.
|
||||
$settings = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, $this->extensionName, $this->pluginName);
|
||||
if (isset($settings['salutation']) && in_array($settings['salutation'], $this->allowedSuffixes, 1)) {
|
||||
$expandedKey = $key . '_' . $settings['salutation'];
|
||||
$value = LocalizationUtility::translate($expandedKey, $this->extensionName, $arguments);
|
||||
}
|
||||
if ($value === null) {
|
||||
$value = LocalizationUtility::translate($key, $this->extensionName, $arguments);
|
||||
}
|
||||
if ($value === null) {
|
||||
$value = $default !== null ? $default : $this->renderChildren();
|
||||
} elseif ($htmlEscape) {
|
||||
$value = htmlspecialchars($value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user