Initial commit - Typo3 11.5.41
This commit is contained in:
479
typo3conf/ext/sr_freecap/ChangeLog
Normal file
479
typo3conf/ext/sr_freecap/ChangeLog
Normal file
@@ -0,0 +1,479 @@
|
||||
2021-03-24 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* Resolves #93424: Audio Captcha without image is not accessible with tab
|
||||
* Add extra array to composer.json
|
||||
|
||||
2020-12-26 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* Resolves #93107: Audio content is output twice
|
||||
* Update version to 2.6.2
|
||||
|
||||
2020-11-22 Stanislas Rolland <typo32020(arobas)sjbr.ca>
|
||||
* Update version to 2.6.1
|
||||
|
||||
2020-10-23 Stanislas Rolland <typo32020(arobas)sjbr.ca>
|
||||
* Resolves #92608: PHP 7.4 issues deprecation notices
|
||||
|
||||
2020-06-15 Stanislas Rolland <typo32020(arobas)sjbr.ca>
|
||||
* Resolves #90636: ConfigurationHelper Select EncryptionAlgorythm does not work
|
||||
* Resolves #89735: RequestMiddlewares.php missing
|
||||
* Update version to 2.5.4
|
||||
* Resolves #91650: Adapt to TYPO3 10 LTS
|
||||
* Update version to 2.6.0
|
||||
|
||||
2019-07-19 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
* Resolves Security Ticket#201907155760000027
|
||||
* Update version to 2.5.3
|
||||
|
||||
2018-11-02 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
* Resolves #86843: Syntax error in class EncryptionUtility
|
||||
* Update version to 2.5.2
|
||||
|
||||
2018-10-24 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
* Resolves #86737: Fix syntax error in class PiBaseApi
|
||||
* Update version to 2.5.1
|
||||
|
||||
2018-10-18 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
* Resolves #86688: Migrate to TYPO3 9 LTS
|
||||
* Update version to 2.5.0
|
||||
|
||||
2018-10-18 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
* Resolves #86691: Incorrect keywords for composer
|
||||
* Update version to 2.4.4
|
||||
|
||||
2018-07-24 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
* Resolves #85628: Error in Spanish localization file
|
||||
* Resolves #85629: Remove dependency on TYPO3 ClientUtility
|
||||
* Resolves #85499: Follow-up to migration from mcrypt to OpenSSL (Thanks to Marcus Bitzl)
|
||||
* Update version to 2.4.3
|
||||
|
||||
2018-04-02 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
* Resolves #84576: Adapt font maker backend module to TYPO3 CMS 7 & 8
|
||||
* Update version to 2.4.2
|
||||
|
||||
2018-04-01 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
* Resolves #83808: Allow translation of invalid input error (Thanks to Christian Toffolo)
|
||||
|
||||
2017-12-20 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
* Update manual
|
||||
|
||||
2017-12-19 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
* Resolves #80906: Unknown Exception thrown when domain model with validator is used in backend context
|
||||
* Resolves #82716: Migrate from mcrypt to openssl (follow-up)
|
||||
* Update version to 2.4.1
|
||||
|
||||
2017-10-16 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
* Resolves #82716: Migrate from mcrypt to openssl
|
||||
* Resolves #81736: Add P3P header for IE 11 of Windows 7 when page opens in popup
|
||||
|
||||
2017-05-28 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
* Resolves #81354: Error code not localized
|
||||
|
||||
2017-01-07 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
|
||||
* Change composer name to sjbr/sr-freecap
|
||||
* Require TYPO3 CMS 7.6 LTS
|
||||
* Resolves #79195: Require zend.multibyte for backend module
|
||||
* Resolves #76062: add freeCap.js via includeJSlibs for compression
|
||||
* Update version to 2.4.0
|
||||
* Update manual
|
||||
|
||||
2016-02-13 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
|
||||
* Resolves #73422: Cleanup in German word list
|
||||
* Resolves #73423: Incorrect audio rendering when using word lists with non-ASCII characters
|
||||
* Resolves #73220: Follow-up to PHP 5.5 warning when decrypting word with blowfish algorithm
|
||||
* Update version to 2.3.1
|
||||
|
||||
2016-02-11 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
|
||||
* Resolves #73394: Replace the English word list
|
||||
|
||||
2016-02-10 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
|
||||
* Resolves #73220: PHP 5.5 warning when decrypting word with blowfish algorithm
|
||||
|
||||
2016-02-01 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
|
||||
* Cleanup in ImageViewHelper
|
||||
* Correction to composer.json
|
||||
* Resolves #73075: Word list used when renewing captcha image is in wrong language
|
||||
|
||||
2015-11-02 Stanislas Rolland <typo(arobas)sjbr.ca>
|
||||
|
||||
* Resolves #70917: An end brace is in excess in TS setup.
|
||||
* Resolves #66194: 500 error in access log
|
||||
|
||||
2015-10-11 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Cleanup
|
||||
* Add composer.json
|
||||
* Move static template registration to TCA overrides
|
||||
* Compatibility with TYPO3 CMS 7
|
||||
* Improve template handling
|
||||
* Cleanup references to versions of TYPO3 CMS lower than 6.2
|
||||
* Delete directory mod1
|
||||
* Update version to 2.3.0
|
||||
|
||||
2015-03-31 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Resolves #64524: SJBR\SrFreecap\Domain\Model\Font raises warning on PHP 5.4+
|
||||
|
||||
2015-03-18 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Resolves #65649: $this->freeCap->checkWord accepts empty postvar
|
||||
* Resolves #64524: SJBR\SrFreecap\Domain\Model\Font raises warning on PHP 5.4+
|
||||
|
||||
2015-02-10 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Resolves #64517: Revert CaptchaValidator::isValid should be protected
|
||||
* Resolves #64972: New view configuration in TYPO3 CMS 6.2
|
||||
* Require TYPO3 CMS 6.2
|
||||
* Update version to 2.2.0
|
||||
|
||||
2015-02-04 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Resolves #64847: Fatal error on CaptchaValidator::isValid() from context PiBaseApi
|
||||
* Update version to 2.1.1
|
||||
|
||||
2015-01-28 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Cleanup
|
||||
|
||||
2015-01-27 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Resolves #64543: Extension does not handle vendorName
|
||||
* Resolves #64525 (Follow-up): Extbase does not find the templates of backend Font Maker in TYPO3 7.0
|
||||
* Resolves #64548: Font file not found in Font Maker on PHP 5.5
|
||||
* Enable in TYPO3 CMS 7
|
||||
* Update version to 2.1.0
|
||||
|
||||
2015-01-26 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Resolves #64517: CaptchaValidator::isValid should be protected
|
||||
* Resolves #64519: Validate annotation: class name TtfFileValidator should not start with backslash
|
||||
* Resolves #64520: Extract module configuration from static template
|
||||
* Resolves #64524: SJBR\SrFreecap\Domain\Model\Font raises warning on PHP 5.4+
|
||||
* Resolves #64525: Extbase does not find the templates of backend Font Maker in TYPO3 7.0
|
||||
|
||||
2014-09-22 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Resolves #61756: Storing session data prevents correct handling of session data in other extensions (Thanks to Daniel Minder)
|
||||
* Update version to 2.0.10
|
||||
|
||||
2014-08-01 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Update version to 2.0.9
|
||||
|
||||
2014-07-29 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Correction to Spanish localization file
|
||||
* Resolves #60536: Mallformed Last-Modified header (Thanks to Christian Ludwig)
|
||||
|
||||
2014-04-14 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Correction to default css styles
|
||||
|
||||
2014-04-08 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Localization of audio captcha may fail for lack of available TCA of pages_language_overlay
|
||||
|
||||
2014-04-02 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Resolves #57543: French text in Italian language file
|
||||
|
||||
2014-02-22 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Cleanup calls to deprecated methods
|
||||
|
||||
2014-02-21 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Resolves #56045: Add random variable in captcha image src
|
||||
* Update version to 2.0.8
|
||||
|
||||
2014-02-13 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Enable in TYPO3 6.2
|
||||
* Update version to 2.0.7
|
||||
|
||||
2014-02-07 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #55777: Object manager exceptions raised in TYPO3 6.2
|
||||
|
||||
2013-11-26 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #51900: Danish locallang file wrongly named
|
||||
* Brazilian locallang file wrongly named
|
||||
* Update version to 2.0.6
|
||||
|
||||
2013-08-08 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #50931: Error in autoload.php
|
||||
* Update version to 2.0.5
|
||||
|
||||
2013-07-10 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Follow-up to bug #47810: Audio Captcha not working under IE 8
|
||||
* Update version to 2.0.4
|
||||
|
||||
2013-07-04 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #47810: Audio Captcha not working under IE 8
|
||||
* Update version to 2.0.3
|
||||
|
||||
2013-06-19 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Added feature #49272: Add support for mp3 audio captcha rendering
|
||||
* Fixed bug #49274: Voice file for digit 3 in Portuguese is broken
|
||||
|
||||
2013-05-24 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed issue #48516: Replace some default fonts for better readability
|
||||
* Fixed issue #48519: Correct/remove some words from French words list
|
||||
* Updated manual
|
||||
* Fixed textual errors in TS static template
|
||||
* Require 6.0.5-6.1.99
|
||||
* Update version to 2.0.1
|
||||
|
||||
2013-05-23 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed issue #48500: Remove superfluous class loader cache entries
|
||||
* Fixed bug #48501: Audio captcha rendering and wordslist selection should apply language fallback rules
|
||||
|
||||
2013-05-07 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #46265: Problem with freecap 2.0.0 and postgreSQL (Thanks to Tilo Baller)
|
||||
|
||||
2013-04-22 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #46648: Filenames for *.wav causes potential problems
|
||||
|
||||
2013-04-20 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #47406: Cleanup in ext_autoload.php
|
||||
* Fixed bug #47407: Keep domain object font ISO-8859-2-encoded
|
||||
* Fixed bug #47408: Incorrect object manager creation
|
||||
|
||||
2013-02-14 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Remove "site tag" feature
|
||||
* Updated version to 2.0.0
|
||||
|
||||
2013-02-13 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Add option to configure the encryption algorithm in Extension Manager
|
||||
* Disable the audio feature on iOS devices
|
||||
* Use object manager to create object instances
|
||||
* Follow-up to use object manager to create object instances
|
||||
|
||||
2013-02-12 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Cleanup audio file rendering
|
||||
* Fix audio player in IE7, IE9 and Opera
|
||||
* Fix audio player in IE8 (but may still be blocked depending on security settings)
|
||||
|
||||
2013-02-11 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Update the manual
|
||||
* Namespace the JavaScript functions
|
||||
|
||||
2013-02-07 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fix max attempts message
|
||||
* Delete unused directories
|
||||
* Fix model html template insert for pi_base plugin
|
||||
|
||||
2013-02-06 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Add translation view helper with formal/informal salutation option
|
||||
* Cleanup configuration files
|
||||
* Add suggested HTML template insert (for pi_base)
|
||||
* Add captcha image and audio icon view helpers
|
||||
* Remove alias on SessionStorage class
|
||||
* Cleanup translation view helper
|
||||
* Require extension vhs 1.5.0
|
||||
* Remove requirement for vhs extension
|
||||
* Fix validation error translation
|
||||
* Cleanup image generator
|
||||
|
||||
2012-12-15 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Add captcha validator class
|
||||
|
||||
2012-12-13 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Migrate backend GD font maker to extbase
|
||||
|
||||
2012-11-15 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Move language labels to private resources directory
|
||||
* Migrate captcha image and audio generation to extbase
|
||||
|
||||
2012-11-10 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Move captcha media to private resources directory
|
||||
* Move javascript to public resources directory
|
||||
* Require TYPO3 6.0
|
||||
|
||||
2012-11-09 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Move original freecap to Contrib directory
|
||||
|
||||
2012-11-06 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fix font maker script character encoding
|
||||
|
||||
2012-11-05 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Migrate localization files to xliff
|
||||
* Migrate font maker module to the use of typo3/mod.php
|
||||
* Add ext_autoload
|
||||
|
||||
2012-03-18 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #32848: Captcha image expiry headers
|
||||
* Fixed bug #34729: Problems with encrypt function (Thanks to Carlos Meyer)
|
||||
* Updated version to 1.5.3
|
||||
|
||||
2011-12-15 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Follow-up to bug #7066: IE embeded media player display
|
||||
* Updated version to 1.5.0
|
||||
* Fixed bug #32604: BE module broken with TYPO3 4.6
|
||||
* Added feature #32610: Russian documentation (Thanks to Андрей Аксенов)
|
||||
* Updated version to 1.5.1
|
||||
* Follow-up to bug #32604: BE module broken with TYPO3 4.6
|
||||
* Updated version to 1.5.2
|
||||
|
||||
2011-12-14 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #7066: IE embeded media player display
|
||||
* Added feature #32567: Use HTML5 audio tag when available
|
||||
* Follow-up to feature #32567: Use HTML5 audio tag when available
|
||||
* Fixed bug #32579: Incorrect length in header of merged wave file
|
||||
|
||||
2011-12-13 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Follow-up to bug #13428: pi1/captcha.php: PHP Fatal Error when called directly
|
||||
* Added feature #32488: Require TYPO3 4.5 and PHP 5.3
|
||||
* Added feature #32524: Remove random number generator seeding
|
||||
* Added feature #32525: Use TYPO3 encryption key
|
||||
* Follow-up to bug #26113: On enter, always the same image is loaded
|
||||
|
||||
2011-12-12 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #32477: Reference to tslib_pibase constructor in tx_srfreecap_pi2
|
||||
* Fixed bug #13428: pi1/captcha.php: PHP Fatal Error when called directly
|
||||
* Fixed bug #13669: ereg/ereg_replace deprecated since PHP 5.3
|
||||
* Fixed bug #27000: error_reporting in pi1/class.tx_srfreecap_pi1.php
|
||||
* Fixed bug #29276: function.mt-rand: max(1) is smaller than min(5)
|
||||
* Fixed bug #26113: On enter, always the same image is loaded
|
||||
* Fixed bug #32487: Remove reference to mediunDoc
|
||||
|
||||
2011-02-15 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #13072: Captcha not showing up when using MP from other domain (Thanks to Ernesto Baschny)
|
||||
* Updated version to 1.4.1
|
||||
|
||||
2011-02-10 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #12921: Audio captcha should be accessible by TAB key (Thanks to Elliot Sawyer)
|
||||
* Require PHP 5.1
|
||||
* Updated manual
|
||||
* Fixed bug #12938: "www.mydomain.org" is not RFC 2606 compilant
|
||||
* Partially fixed bug #5628: Political (In-)Correctness of the german word list
|
||||
* Updated version to 1.4.0
|
||||
|
||||
2011-02-01 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Added feature #12714: Add TS constants to control darkness of the captcha text. Thanks to Julia Pardanaud.
|
||||
* Added feature #12716: New default values of TS constants to increase CAPTCHA readability. Thanks to Julia Pardanaud.
|
||||
|
||||
2010-12-21 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #10223: BE module not shown anymore with TYPO3 4.4
|
||||
* Fixed bug #8528: Typo in Dutch localization of label in pi2/locallang.xml
|
||||
* Fixed bug #7987: maxWordLength problem
|
||||
|
||||
2010-04-16 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Require TYPO3 4.3
|
||||
* Manual updated.
|
||||
* Updated ext_emconf from TER version 1.2.3
|
||||
|
||||
2010-04-14 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #7259: Use of deprecated function t3lib_div::makeInstanceClassName()
|
||||
|
||||
2009-10-20 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug: Mishandling of session data. Thanks to Wolo Wolski.
|
||||
* Updated ext_emconf from TER version 1.2.2
|
||||
* Updated manual.
|
||||
|
||||
2009-08-31 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Added feature: new TS constant accessibleOutputImage and textual version.
|
||||
* Manual updated.
|
||||
* Updated ext_emconf from TER version 1.2.0
|
||||
|
||||
2009-08-29 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Follow-up to #3056: Audio Captcha is not rendered in IE8
|
||||
* Added feature: Two new TS constants: textHorizontalPosition and textVerticalPosition. Thanks to Julia Pardanaud.
|
||||
* Added Turkish word list. Thanks to Zeynep Nurten Cinarcik.
|
||||
|
||||
2009-06-03 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #3056: Audio Captcha is not rendered in IE8
|
||||
|
||||
2009-06-01 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Added feature #3526: Use eID API for graphical and audio captcha generation.
|
||||
* Follow-up to #3526 for TYPO3 < 4.3: Use eID API for graphical and audio captcha generation.
|
||||
* Fixed bug #3530: Morphed image blocks background type not working.
|
||||
* Follow-up to feature #3526: Cleanup parameters of new captcha image
|
||||
|
||||
2009-05-29 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #3472: No image rendering in T3 V4.3 alpha3.
|
||||
|
||||
2009-05-07 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Added feature #3244: User can set the width of the generated captcha-image. Thanks to Simon Schick.
|
||||
|
||||
2009-04-15 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Added Russian translation. Thanks to Андрей Аксенов.
|
||||
|
||||
2009-04-07 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Fixed bug #3052: "onclick" should be used instead of "onClick". Thanks to Gerald Schwarz.
|
||||
* Fixed bug: Random number generator should be seeded.
|
||||
|
||||
2009-04-01 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Removed some words from the default word list.
|
||||
* Added partial Russian translation. Thanks to Esben Fest.
|
||||
* Updated manual.
|
||||
* Updated ext_emconf from TER version 1.1.2
|
||||
|
||||
2009-01-24 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Updated manual.
|
||||
* Updated ext_emconf from TER version 1.1.1
|
||||
|
||||
2009-01-23 Stanislas Rolland <typo3@sjbr.ca>
|
||||
|
||||
* Initial upload to TYPO3 Forge
|
||||
* Cleanup: Use UNIX line separators in all files
|
||||
* Fix for current TYPO3 trunk (4.3-dev) caching
|
||||
* Update version number to 1.1.1
|
||||
* Default to local installation
|
||||
* Fixed bug #10132: sr_freecap seems to work only with default language. Thanks to Dan Grünzig.
|
||||
* Follow-up to issue #10132: Adding comments
|
||||
* Added Polish translation. Thanks to Daniel Ciunkiewicz.
|
||||
* Correction to the manual. Thanks to Niklas Kanthak.
|
||||
* Remove superfluous spaces in rendered html. Thanks to Niklas Kanthak.
|
||||
* ###SR_FREECAP_ACCESSIBLE### marker should produce inline html. Audio object wrapper changed from div to span. Thanks to Niklas Kanthak.
|
||||
* Updated manual: random background type does not exist anymore with freecap 1.4.
|
||||
* Added missing images for Morphed image blocks option of backgroundType.
|
||||
* Updated damaged images.
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* An array consisting of implementations of middlewares for a middleware stack to be registered
|
||||
*
|
||||
* 'stackname' => [
|
||||
* 'middleware-identifier' => [
|
||||
* 'target' => classname or callable
|
||||
* 'before/after' => array of dependencies
|
||||
* ]
|
||||
* ]
|
||||
*/
|
||||
return [
|
||||
'frontend' => [
|
||||
'sjbr/sr-freecap/eidsr' => [
|
||||
'target' => \SJBR\SrFreecap\Middleware\EidHandler::class,
|
||||
'after' => [
|
||||
'typo3/cms-frontend/tsfe',
|
||||
'typo3/cms-frontend/authentication',
|
||||
'typo3/cms-frontend/backend-user-authentication',
|
||||
'typo3/cms-frontend/site',
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
13
typo3conf/ext/sr_freecap/Configuration/Services.yaml
Normal file
13
typo3conf/ext/sr_freecap/Configuration/Services.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
# Configuration/Services.yaml
|
||||
services:
|
||||
_defaults:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
public: false
|
||||
|
||||
SJBR\SrFreecap\:
|
||||
resource: '../Classes/*'
|
||||
exclude: '../Classes/Domain/Model/*'
|
||||
|
||||
SJBR\SrFreecap\Configuration\ConfigurationHelper:
|
||||
public: true
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
defined('TYPO3') or die();
|
||||
|
||||
// Register SrFreecap static template
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('sr_freecap', 'Configuration/TypoScript', 'freeCap CAPTCHA');
|
||||
@@ -0,0 +1,9 @@
|
||||
## Configuring the Font Maker backend module
|
||||
module.tx_srfreecap {
|
||||
## Paths for backend templates
|
||||
view {
|
||||
templateRootPaths.0 = EXT:sr_freecap/Resources/Private/Backend/Templates/
|
||||
partialRootPaths.0 = EXT:sr_freecap/Resources/Private/Backend/Partials/
|
||||
layoutRootPaths.0 = EXT:sr_freecap/Resources/Private/Backend/Layouts/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
plugin.tx_srfreecap {
|
||||
|
||||
# cat=plugin.tx_srfreecap/dims/02; type=int+; label= CAPTCHA image height: Height of the generated image.
|
||||
imageHeight = 90
|
||||
|
||||
# cat=plugin.tx_srfreecap/dims/03; type=int+; label= CAPTCHA image additional width: The width, in pixels, of the generated image is based on the maximum possible length of the word plus the value of this property.
|
||||
imageAdditionalWidth = 30
|
||||
|
||||
# cat=plugin.tx_srfreecap/dims/04; type=int+; label= The horizontal (X) starting position of the word relative to the left of the image, in pixels.
|
||||
textHorizontalPosition = 1
|
||||
|
||||
# cat=plugin.tx_srfreecap/dims/05; type=int+; label= The vertical (Y) starting position of the word relative to the top of the image, in pixels.
|
||||
textVerticalPosition = 15
|
||||
|
||||
# cat=plugin.tx_srfreecap/dims/01; type=int[5-50]; label= Maximun word length: Maximun length of the randomly generated CAPTCHA string.
|
||||
maxWordLength = 5
|
||||
|
||||
# cat=plugin.tx_srfreecap/color; type=boolean; label= Color of the text: 0=one random colour for all letters, 1=different random colour for each letter.
|
||||
textColor = 0
|
||||
|
||||
# cat=plugin.tx_srfreecap/color; type=int[0-255]; label= Maximum darkness of the text color: The lower the number, the darker the color of the text may be.
|
||||
colorMaximumDarkness = 5
|
||||
|
||||
# cat=plugin.tx_srfreecap/color; type=int[0-255]; label= Maximum lightness of the text color: The higher the number, the lighter the color of the text may be.
|
||||
colorMaximumLightness = 50
|
||||
|
||||
# cat=plugin.tx_srfreecap//03; type=options[png,gif,jpg]; label= CAPTCHA image format: Format of the generated image.
|
||||
imageFormat = png
|
||||
|
||||
# cat=plugin.tx_srfreecap/enable/01; type=boolean; label= Use list of words: If enabled, the CAPTCHA string will be selected from a list of words. If not, it will be randomly generated.
|
||||
useWordsList = 0
|
||||
|
||||
# cat=plugin.tx_srfreecap/enable/02; type=boolean; label= Generate CAPTCHA with numbers only. This option is ignored if Use list of words is enabled.
|
||||
generateNumbers = 0
|
||||
|
||||
# cat=plugin.tx_srfreecap//01; type=int+; label= Maximun attempts: Maximum times a user can refresh the image.
|
||||
maxAttempts = 100
|
||||
|
||||
# cat=plugin.tx_srfreecap//04; type=options[,Transparent,White with grid,White with squiggles,Morphed image blocks]; label= Background type: If not set, will be random selection of possible types.
|
||||
backgroundType = White with grid
|
||||
|
||||
# cat=plugin.tx_srfreecap/enable/04; type=boolean; label= Background blurring: If enabled, the background will be blurred. The string should be easier to read.
|
||||
backgroundBlur = 1
|
||||
|
||||
# cat=plugin.tx_srfreecap/enable/05; type=boolean; label= Background morphing: If enabled, the background will be morphed (recommended).
|
||||
backgroundMorph = 0
|
||||
|
||||
# cat=plugin.tx_srfreecap/enable/06; type=boolean; label= Merge string with background: 0=write CAPTCHA string over background, 1=merge CAPTCHA string with non-transparent background.
|
||||
mergeWithBackground = 0
|
||||
|
||||
# cat=plugin.tx_srfreecap//05; type=string; label= Text morphing factor: Morphing factor applied to each character of the CAPTCHA string.
|
||||
morphFactor = 0.1
|
||||
|
||||
# cat=plugin.tx_srfreecap/file/01; type=file[]; label= Default words list file: All words lists should be in the same directory.
|
||||
defaultWordsList = EXT:sr_freecap/Resources/Private/Captcha/Words/default_freecap_words
|
||||
|
||||
# cat=plugin.tx_srfreecap//02; type=options[,formal,informal]; label= Type of salutation to use: Possible values are 'formal' or 'informal'.
|
||||
salutation =
|
||||
|
||||
# cat=plugin.tx_srfreecap/file/02; type=string; label= List of GD font files: Coma-separated list of GD font files located in directory uploads/tx_srfreecap/ or in some extension directory using the usual syntax EXT:extensionKey/etc.
|
||||
fontFiles =
|
||||
|
||||
# cat=plugin.tx_srfreecap/enable/03; type=boolean; label= Accessible output: If enabled, the CAPTCHA will include an audio version.
|
||||
accessibleOutput = 0
|
||||
|
||||
# cat=plugin.tx_srfreecap/file/03; type=string; label= Accessible output image: File name of the accessible output image. If null, a textual message is used.
|
||||
accessibleOutputImage = EXT:sr_freecap/Resources/Public/Images/audio.png
|
||||
|
||||
view {
|
||||
# cat=plugin.tx_srfreecap/file; type=string; label=Path to template partials (FE)
|
||||
partialRootPath = EXT:sr_freecap/Resources/Private/Partials/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
## Configuring the frontend rendering
|
||||
plugin.tx_srfreecap {
|
||||
settings {
|
||||
imageHeight = {$plugin.tx_srfreecap.imageHeight}
|
||||
imageAdditionalWidth = {$plugin.tx_srfreecap.imageAdditionalWidth}
|
||||
imageFormat = {$plugin.tx_srfreecap.imageFormat}
|
||||
|
||||
textHorizontalPosition = {$plugin.tx_srfreecap.textHorizontalPosition}
|
||||
textVerticalPosition = {$plugin.tx_srfreecap.textVerticalPosition}
|
||||
|
||||
backgroundType = {$plugin.tx_srfreecap.backgroundType}
|
||||
backgroundBlur = {$plugin.tx_srfreecap.backgroundBlur}
|
||||
backgroundMorph = {$plugin.tx_srfreecap.backgroundMorph}
|
||||
|
||||
maxWordLength = {$plugin.tx_srfreecap.maxWordLength}
|
||||
useWordsList = {$plugin.tx_srfreecap.useWordsList}
|
||||
generateNumbers = {$plugin.tx_srfreecap.generateNumbers}
|
||||
|
||||
colorMaximumDarkness = {$plugin.tx_srfreecap.colorMaximumDarkness}
|
||||
colorMaximumLightness = {$plugin.tx_srfreecap.colorMaximumLightness}
|
||||
textColor = {$plugin.tx_srfreecap.textColor}
|
||||
mergeWithBackground = {$plugin.tx_srfreecap.mergeWithBackground}
|
||||
morphFactor = {$plugin.tx_srfreecap.morphFactor}
|
||||
defaultWordsList = {$plugin.tx_srfreecap.defaultWordsList}
|
||||
fontFiles = {$plugin.tx_srfreecap.fontFiles}
|
||||
|
||||
maxAttempts = {$plugin.tx_srfreecap.maxAttempts}
|
||||
|
||||
accessibleOutput = {$plugin.tx_srfreecap.accessibleOutput}
|
||||
accessibleOutputImage = {$plugin.tx_srfreecap.accessibleOutputImage}
|
||||
|
||||
salutation = {$plugin.tx_srfreecap.salutation}
|
||||
}
|
||||
view {
|
||||
partialRootPaths {
|
||||
0 = EXT:sr_freecap/Resources/Private/Partials/
|
||||
1 = {$plugin.tx_srfreecap.view.partialRootPath}
|
||||
}
|
||||
}
|
||||
_CSS_DEFAULT_STYLE (
|
||||
.tx-srfreecap-captcha label { display: inline-block; width: 150px; }
|
||||
img.tx-srfreecap-image { margin-left: 1em; margin-right: 1em; vertical-align: middle; }
|
||||
.tx-srfreecap-image-accessible {
|
||||
background-color: transparent;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.tx-srfreecap-accessible-link { width: 10em; float: right; vertical-align: middle; margin-right: 7em; }
|
||||
.tx-srfreecap-cant-read { display: inline-block; width: 150px; }
|
||||
.tx-srfreecap-cant-read a:link { background-color:transparent; font-weight:bold; text-decoration:none; }
|
||||
)
|
||||
}
|
||||
|
||||
## Backward pi_base compatibility
|
||||
plugin.tx_srfreecap_pi2 {
|
||||
_CSS_DEFAULT_STYLE (
|
||||
.tx-srfreecap-pi1-captcha label { display: inline-block; width: 150px; }
|
||||
img.tx-srfreecap-pi1-image { margin-left: 1em; margin-right: 1em; vertical-align: middle; }
|
||||
.tx-srfreecap-pi1-image-accessible {
|
||||
background-color: transparent;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.tx-srfreecap-pi1-accessible-link { width: 10em; float: right; vertical-align: middle; margin-right: 7em; }
|
||||
.tx-srfreecap-pi1-cant-read { display: inline-block; width: 150px; }
|
||||
.tx-srfreecap-pi1-cant-read a:link { background-color:transparent; font-weight:bold; text-decoration:none; }
|
||||
)
|
||||
}
|
||||
1
typo3conf/ext/sr_freecap/Contrib/.htaccess
Normal file
1
typo3conf/ext/sr_freecap/Contrib/.htaccess
Normal file
@@ -0,0 +1 @@
|
||||
deny from all
|
||||
340
typo3conf/ext/sr_freecap/Contrib/freeCap-1.4.1/COPYING.txt
Normal file
340
typo3conf/ext/sr_freecap/Contrib/freeCap-1.4.1/COPYING.txt
Normal file
@@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
817
typo3conf/ext/sr_freecap/Contrib/freeCap-1.4.1/freecap141.php
Normal file
817
typo3conf/ext/sr_freecap/Contrib/freeCap-1.4.1/freecap141.php
Normal file
@@ -0,0 +1,817 @@
|
||||
<?
|
||||
/************************************************************\
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*
|
||||
\************************************************************/
|
||||
|
||||
session_start();
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
////// User Defined Vars:
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// try to avoid the 'free p*rn' method of CAPTCHA circumvention
|
||||
// see www.wikipedia.com/captcha for more info
|
||||
$site_tags[0] = "To avoid spam, please do NOT enter the text if";
|
||||
$site_tags[1] = "this site is not puremango.co.uk";
|
||||
// or more simply:
|
||||
//$site_tags[0] = "for use only on puremango.co.uk";
|
||||
// reword or add lines as you please
|
||||
// or if you don't want any text:
|
||||
$site_tags = null;
|
||||
|
||||
// where to write the above:
|
||||
// 0=top
|
||||
// 1=bottom
|
||||
// 2=both
|
||||
$tag_pos = 1;
|
||||
|
||||
// functions to call for random number generation
|
||||
// mt_rand produces 'better' random numbers
|
||||
// but if your server doesn't support it, it's fine to use rand instead
|
||||
$rand_func = "mt_rand";
|
||||
$seed_func = "mt_srand";
|
||||
|
||||
// which type of hash to use?
|
||||
// possible values: "sha1", "md5", "crc32"
|
||||
// sha1 supported by PHP4.3.0+
|
||||
// md5 supported by PHP3+
|
||||
// crc32 supported by PHP4.0.1+
|
||||
$hash_func = "sha1";
|
||||
// store in session so can validate in form processor
|
||||
$_SESSION['hash_func'] = $hash_func;
|
||||
|
||||
// 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.
|
||||
$output = "png";
|
||||
|
||||
// 0=generate pseudo-random string, 1=use dictionary
|
||||
// dictionary is easier to recognise
|
||||
// - both for humans and computers, so use random string if you're paranoid.
|
||||
$use_dict = 1;
|
||||
// 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
|
||||
$dict_location = "./.ht_freecap_words";
|
||||
|
||||
// used to calculate image width, and for non-dictionary word generation
|
||||
$max_word_length = 6;
|
||||
|
||||
// text colour
|
||||
// 0=one random colour for all letters
|
||||
// 1=different random colour for each letter
|
||||
$col_type = 1;
|
||||
|
||||
// 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
|
||||
$max_attempts = 20;
|
||||
|
||||
// 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
|
||||
$font_locations = Array("./.ht_freecap_font1.gdf","./.ht_freecap_font2.gdf","./.ht_freecap_font3.gdf","./.ht_freecap_font4.gdf","./.ht_freecap_font5.gdf");
|
||||
|
||||
// background:
|
||||
// 0=transparent (if jpg, white)
|
||||
// 1=white bg with grid
|
||||
// 2=white bg with squiggles
|
||||
// 3=morphed image blocks
|
||||
// 'random' background from v1.3 didn't provide any extra security (according to 2 independent experts)
|
||||
// many thanks to http://ocr-research.org.ua and http://sam.zoy.org/pwntcha/ for testing
|
||||
// for jpgs, 'transparent' is white
|
||||
$bg_type = 2;
|
||||
// should we blur the background? (looks nicer, makes text easier to read, takes longer)
|
||||
$blur_bg = false;
|
||||
// for bg_type 3, which images should we use?
|
||||
// if you add your own, make sure they're fairly 'busy' images (ie a lot of shapes in them)
|
||||
$bg_images = Array("./.ht_freecap_im1.jpg","./.ht_freecap_im2.jpg","./.ht_freecap_im3.jpg","./.ht_freecap_im4.jpg","./.ht_freecap_im5.jpg");
|
||||
// for non-transparent backgrounds only:
|
||||
// if 0, merges CAPTCHA with bg
|
||||
// if 1, write CAPTCHA over bg
|
||||
$merge_type = 0;
|
||||
// should we morph the bg? (recommend yes, but takes a little longer to compute)
|
||||
$morph_bg = true;
|
||||
|
||||
// you shouldn't need to edit anything below this, but it's extensively commented if you do want to play
|
||||
// have fun, and email me with ideas, or improvements to the code (very interested in speed improvements)
|
||||
// hope this script saves some spam :-)
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
////// Create Images + initialise a few things
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// seed random number generator
|
||||
// PHP 4.2.0+ doesn't need this, but lower versions will
|
||||
$seed_func(make_seed());
|
||||
|
||||
// how faded should the bg 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 bg, then it's not a good enough percentage
|
||||
switch($bg_type)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
$bg_fade_pct = 65;
|
||||
break;
|
||||
case 3:
|
||||
$bg_fade_pct = 50;
|
||||
break;
|
||||
}
|
||||
// slightly randomise the bg fade
|
||||
$bg_fade_pct += $rand_func(-2,2);
|
||||
|
||||
// read each font and get font character widths
|
||||
$font_widths = Array();
|
||||
for($i=0 ; $i<sizeof($font_locations) ; $i++)
|
||||
{
|
||||
$handle = fopen($font_locations[$i],"r");
|
||||
// read header of GD font, up to char width
|
||||
$c_wid = fread($handle,11);
|
||||
$font_widths[$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.
|
||||
$width = ($max_word_length*(array_sum($font_widths)/sizeof($font_widths))+75);
|
||||
$height = 90;
|
||||
|
||||
$im = ImageCreate($width, $height);
|
||||
$im2 = ImageCreate($width, $height);
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
////// Avoid Brute Force Attacks:
|
||||
//////////////////////////////////////////////////////
|
||||
if(empty($_SESSION['freecap_attempts']))
|
||||
{
|
||||
$_SESSION['freecap_attempts'] = 1;
|
||||
} else {
|
||||
$_SESSION['freecap_attempts']++;
|
||||
|
||||
// if more than ($max_attempts) 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($_SESSION['freecap_attempts']>$max_attempts)
|
||||
{
|
||||
$_SESSION['freecap_word_hash'] = false;
|
||||
|
||||
$bg = ImageColorAllocate($im,255,255,255);
|
||||
ImageColorTransparent($im,$bg);
|
||||
|
||||
$red = ImageColorAllocate($im, 255, 0, 0);
|
||||
// depending on how rude you want to be :-)
|
||||
//ImageString($im,5,0,20,"bugger off you spamming bastards!",$red);
|
||||
ImageString($im,5,15,20,"service no longer available",$red);
|
||||
|
||||
sendImage($im);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
////// Functions:
|
||||
//////////////////////////////////////////////////////
|
||||
function make_seed() {
|
||||
// from http://php.net/srand
|
||||
list($usec, $sec) = explode(' ', microtime());
|
||||
return (float) $sec + ((float) $usec * 100000);
|
||||
}
|
||||
|
||||
function rand_color() {
|
||||
global $bg_type,$rand_func;
|
||||
if($bg_type==3)
|
||||
{
|
||||
// needs darker colour..
|
||||
return $rand_func(10,100);
|
||||
} else {
|
||||
return $rand_func(60,170);
|
||||
}
|
||||
}
|
||||
|
||||
function myImageBlur($im)
|
||||
{
|
||||
// w00t. my very own blur function
|
||||
// in GD2, there's a gaussian blur function. bunch of bloody show-offs... :-)
|
||||
|
||||
$width = imagesx($im);
|
||||
$height = imagesy($im);
|
||||
|
||||
$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, $im, 0, 0, 0, $distance, $width, $height-$distance, 70);
|
||||
ImageCopyMerge($im, $temp_im, 0, 0, $distance, 0, $width-$distance, $height, 70);
|
||||
ImageCopyMerge($temp_im, $im, 0, $distance, 0, 0, $width, $height, 70);
|
||||
ImageCopyMerge($im, $temp_im, $distance, 0, 0, 0, $width, $height, 70);
|
||||
// remove temp image
|
||||
ImageDestroy($temp_im);
|
||||
|
||||
return $im;
|
||||
}
|
||||
|
||||
function sendImage($pic)
|
||||
{
|
||||
// output image with appropriate headers
|
||||
global $output,$im,$im2,$im3;
|
||||
header(base64_decode("WC1DYXB0Y2hhOiBmcmVlQ2FwIDEuNCAtIHd3dy5wdXJlbWFuZ28uY28udWs="));
|
||||
switch($output)
|
||||
{
|
||||
// add other cases as desired
|
||||
case "jpg":
|
||||
header("Content-Type: image/jpeg");
|
||||
ImageJPEG($pic);
|
||||
break;
|
||||
case "gif":
|
||||
header("Content-Type: image/gif");
|
||||
ImageGIF($pic);
|
||||
break;
|
||||
case "png":
|
||||
default:
|
||||
header("Content-Type: image/png");
|
||||
ImagePNG($pic);
|
||||
break;
|
||||
}
|
||||
|
||||
// kill GD images (removes from memory)
|
||||
ImageDestroy($im);
|
||||
ImageDestroy($im2);
|
||||
ImageDestroy($pic);
|
||||
if(!empty($im3))
|
||||
{
|
||||
ImageDestroy($im3);
|
||||
}
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
////// Choose Word:
|
||||
//////////////////////////////////////////////////////
|
||||
if($use_dict==1)
|
||||
{
|
||||
// load dictionary and choose random word
|
||||
$words = @file($dict_location);
|
||||
$word = strtolower($words[$rand_func(0,sizeof($words)-1)]);
|
||||
// cut off line endings/other possible odd chars
|
||||
$word = preg_replace('/[^a-z]/', '',$word);
|
||||
// might be large file so forget it now (frees memory)
|
||||
$words = "";
|
||||
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)
|
||||
$consonants = 'bcdghklmnpqrsvwxyz';
|
||||
$vowels = 'aeuo';
|
||||
$word = "";
|
||||
|
||||
$wordlen = $rand_func(5,$max_word_length);
|
||||
|
||||
for($i=0 ; $i<$wordlen ; $i++)
|
||||
{
|
||||
// don't allow to start with 'vowel'
|
||||
if($rand_func(0,4)>=2 && $i!=0)
|
||||
{
|
||||
$word .= $vowels{$rand_func(0,strlen($vowels)-1)};
|
||||
} else {
|
||||
$word .= $consonants{$rand_func(0,strlen($consonants)-1)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
$_SESSION['freecap_word_hash'] = $hash_func($word);
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
////// Fill BGs and Allocate Colours:
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// set tag colour
|
||||
// have to do this before any distortion
|
||||
// (otherwise colour allocation fails when bg type is 1)
|
||||
$tag_col = ImageColorAllocate($im,10,10,10);
|
||||
$site_tag_col2 = ImageColorAllocate($im2,0,0,0);
|
||||
|
||||
// set debug colours (text colours are set later)
|
||||
$debug = ImageColorAllocate($im, 255, 0, 0);
|
||||
$debug2 = ImageColorAllocate($im2, 255, 0, 0);
|
||||
|
||||
// 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 bg_type 3, you might want to try to ensure that the color chosen
|
||||
// below doesn't appear too much in any of your background images.
|
||||
$bg = ImageColorAllocate($im, 254, 254, 254);
|
||||
$bg2 = ImageColorAllocate($im2, 254, 254, 254);
|
||||
|
||||
// set transparencies
|
||||
ImageColorTransparent($im,$bg);
|
||||
// im2 transparent to allow characters to overlap slightly while morphing
|
||||
ImageColorTransparent($im2,$bg2);
|
||||
|
||||
// fill backgrounds
|
||||
ImageFill($im,0,0,$bg);
|
||||
ImageFill($im2,0,0,$bg2);
|
||||
|
||||
if($bg_type!=0)
|
||||
{
|
||||
// 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!
|
||||
|
||||
$im3 = ImageCreateTrueColor($width,$height);
|
||||
$temp_bg = ImageCreateTrueColor($width*1.5,$height*1.5);
|
||||
$bg3 = ImageColorAllocate($im3,255,255,255);
|
||||
ImageFill($im3,0,0,$bg3);
|
||||
$temp_bg_col = ImageColorAllocate($temp_bg,255,255,255);
|
||||
ImageFill($temp_bg,0,0,$temp_bg_col);
|
||||
|
||||
// we draw all noise onto temp_bg
|
||||
// then if we're morphing, merge from temp_bg to im3
|
||||
// or if not, just copy a $widthx$height portion of $temp_bg to $im3
|
||||
// temp_bg is much larger so that when morphing, the edges retain the noise.
|
||||
|
||||
if($bg_type==1)
|
||||
{
|
||||
// grid bg:
|
||||
|
||||
// draw grid on x
|
||||
for($i=$rand_func(6,20) ; $i<$width*2 ; $i+=$rand_func(10,25))
|
||||
{
|
||||
ImageSetThickness($temp_bg,$rand_func(2,6));
|
||||
$text_r = $rand_func(100,150);
|
||||
$text_g = $rand_func(100,150);
|
||||
$text_b = $rand_func(100,150);
|
||||
$text_colour3 = ImageColorAllocate($temp_bg, $text_r, $text_g, $text_b);
|
||||
|
||||
ImageLine($temp_bg,$i,0,$i,$height*2,$text_colour3);
|
||||
}
|
||||
// draw grid on y
|
||||
for($i=$rand_func(6,20) ; $i<$height*2 ; $i+=$rand_func(10,25))
|
||||
{
|
||||
ImageSetThickness($temp_bg,$rand_func(2,6));
|
||||
$text_r = $rand_func(100,150);
|
||||
$text_g = $rand_func(100,150);
|
||||
$text_b = $rand_func(100,150);
|
||||
$text_colour3 = ImageColorAllocate($temp_bg, $text_r, $text_g, $text_b);
|
||||
|
||||
ImageLine($temp_bg,0,$i,$width*2, $i ,$text_colour3);
|
||||
}
|
||||
} else if($bg_type==2) {
|
||||
// draw squiggles!
|
||||
|
||||
$bg3 = ImageColorAllocate($im3,255,255,255);
|
||||
ImageFill($im3,0,0,$bg3);
|
||||
ImageSetThickness($temp_bg,4);
|
||||
|
||||
for($i=0 ; $i<strlen($word)+1 ; $i++)
|
||||
{
|
||||
$text_r = $rand_func(100,150);
|
||||
$text_g = $rand_func(100,150);
|
||||
$text_b = $rand_func(100,150);
|
||||
$text_colour3 = ImageColorAllocate($temp_bg, $text_r, $text_g, $text_b);
|
||||
|
||||
$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<$rand_func(5,10) ; $j++)
|
||||
{
|
||||
$points[] = $rand_func(1*(20*($i+1)),1*(50*($i+1)));
|
||||
$points[] = $rand_func(30,$height+30);
|
||||
}
|
||||
|
||||
ImagePolygon($temp_bg,$points,intval(sizeof($points)/2),$text_colour3);
|
||||
}
|
||||
|
||||
} else if($bg_type==3) {
|
||||
// take random chunks of $bg_images and paste them onto the background
|
||||
|
||||
for($i=0 ; $i<sizeof($bg_images) ; $i++)
|
||||
{
|
||||
// read each image and its size
|
||||
$temp_im[$i] = ImageCreateFromJPEG($bg_images[$i]);
|
||||
$temp_width[$i] = imagesx($temp_im[$i]);
|
||||
$temp_height[$i] = imagesy($temp_im[$i]);
|
||||
}
|
||||
|
||||
$blocksize = $rand_func(20,60);
|
||||
for($i=0 ; $i<$width*2 ; $i+=$blocksize)
|
||||
{
|
||||
// could randomise blocksize here... hardly matters
|
||||
for($j=0 ; $j<$height*2 ; $j+=$blocksize)
|
||||
{
|
||||
$image_index = $rand_func(0,sizeof($temp_im)-1);
|
||||
$cut_x = $rand_func(0,$temp_width[$image_index]-$blocksize);
|
||||
$cut_y = $rand_func(0,$temp_height[$image_index]-$blocksize);
|
||||
ImageCopy($temp_bg, $temp_im[$image_index], $i, $j, $cut_x, $cut_y, $blocksize, $blocksize);
|
||||
}
|
||||
}
|
||||
for($i=0 ; $i<sizeof($temp_im) ; $i++)
|
||||
{
|
||||
// remove bgs from memory
|
||||
ImageDestroy($temp_im[$i]);
|
||||
}
|
||||
|
||||
// for debug:
|
||||
//sendImage($temp_bg);
|
||||
}
|
||||
|
||||
// for debug:
|
||||
//sendImage($im3);
|
||||
|
||||
if($morph_bg)
|
||||
{
|
||||
// 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 bg, it would un-morph the CAPTCHA
|
||||
// hence bg 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 bg.
|
||||
$morph_chunk = $rand_func(1,5);
|
||||
$morph_y = 0;
|
||||
for($x=0 ; $x<$width ; $x+=$morph_chunk)
|
||||
{
|
||||
$morph_chunk = $rand_func(1,5);
|
||||
$morph_y += $rand_func(-1,1);
|
||||
ImageCopy($im3, $temp_bg, $x, 0, $x+30, 30+$morph_y, $morph_chunk, $height*2);
|
||||
}
|
||||
|
||||
ImageCopy($temp_bg, $im3, 0, 0, 0, 0, $width, $height);
|
||||
|
||||
$morph_x = 0;
|
||||
for($y=0 ; $y<=$height; $y+=$morph_chunk)
|
||||
{
|
||||
$morph_chunk = $rand_func(1,5);
|
||||
$morph_x += $rand_func(-1,1);
|
||||
ImageCopy($im3, $temp_bg, $morph_x, $y, 0, $y, $width, $morph_chunk);
|
||||
|
||||
}
|
||||
} else {
|
||||
// just copy temp_bg onto im3
|
||||
ImageCopy($im3,$temp_bg,0,0,30,30,$width,$height);
|
||||
}
|
||||
|
||||
ImageDestroy($temp_bg);
|
||||
|
||||
if($blur_bg)
|
||||
{
|
||||
myImageBlur($im3);
|
||||
}
|
||||
}
|
||||
// for debug:
|
||||
//sendImage($im3);
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
////// Write Word
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// write word in random starting X position
|
||||
$word_start_x = $rand_func(5,32);
|
||||
// y positions jiggled about later
|
||||
$word_start_y = 15;
|
||||
|
||||
if($col_type==0)
|
||||
{
|
||||
$text_r = rand_color();
|
||||
$text_g = rand_color();
|
||||
$text_b = rand_color();
|
||||
$text_colour2 = ImageColorAllocate($im2, $text_r, $text_g, $text_b);
|
||||
}
|
||||
|
||||
// write each char in different font
|
||||
for($i=0 ; $i<strlen($word) ; $i++)
|
||||
{
|
||||
if($col_type==1)
|
||||
{
|
||||
$text_r = rand_color();
|
||||
$text_g = rand_color();
|
||||
$text_b = rand_color();
|
||||
$text_colour2 = ImageColorAllocate($im2, $text_r, $text_g, $text_b);
|
||||
}
|
||||
|
||||
$j = $rand_func(0,sizeof($font_locations)-1);
|
||||
$font = ImageLoadFont($font_locations[$j]);
|
||||
ImageString($im2, $font, $word_start_x+($font_widths[$j]*$i), $word_start_y, $word{$i}, $text_colour2);
|
||||
}
|
||||
// use last pixelwidth
|
||||
$font_pixelwidth = $font_widths[$j];
|
||||
|
||||
// for debug:
|
||||
//sendImage($im2);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
////// Morph Image:
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// calculate how big the text is in pixels
|
||||
// (so we only morph what we need to)
|
||||
$word_pix_size = $word_start_x+(strlen($word)*$font_pixelwidth);
|
||||
|
||||
// firstly move each character up or down a bit:
|
||||
for($i=$word_start_x ; $i<$word_pix_size ; $i+=$font_pixelwidth)
|
||||
{
|
||||
// move on Y axis
|
||||
// deviates at least 4 pixels between each letter
|
||||
$prev_y = $y_pos;
|
||||
do{
|
||||
$y_pos = $rand_func(-5,5);
|
||||
} while($y_pos<$prev_y+2 && $y_pos>$prev_y-2);
|
||||
ImageCopy($im, $im2, $i, $y_pos, $i, 0, $font_pixelwidth, $height);
|
||||
|
||||
// for debug:
|
||||
//ImageRectangle($im,$i,$y_pos+10,$i+$font_pixelwidth,$y_pos+70,$debug);
|
||||
}
|
||||
|
||||
// for debug:
|
||||
//sendImage($im);
|
||||
|
||||
ImageFilledRectangle($im2,0,0,$width,$height,$bg2);
|
||||
|
||||
// randomly morph each character individually on x-axis
|
||||
// this is where the main distortion happens
|
||||
// massively improved since v1.2
|
||||
$y_chunk = 1;
|
||||
$morph_factor = 1;
|
||||
$morph_x = 0;
|
||||
for($j=0 ; $j<strlen($word) ; $j++)
|
||||
{
|
||||
$y_pos = 0;
|
||||
for($i=0 ; $i<=$height; $i+=$y_chunk)
|
||||
{
|
||||
$orig_x = $word_start_x+($j*$font_pixelwidth);
|
||||
// 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 += $rand_func(-$morph_factor,$morph_factor);
|
||||
// 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($im2, $im, $orig_x+$morph_x, $i+$y_pos, $orig_x, $i, $font_pixelwidth, $y_chunk, 100);
|
||||
|
||||
// for debug:
|
||||
//ImageLine($im2, $orig_x+$morph_x, $i, $orig_x+$morph_x+1, $i+$y_chunk, $debug2);
|
||||
//ImageLine($im2, $orig_x+$morph_x+$font_pixelwidth, $i, $orig_x+$morph_x+$font_pixelwidth+1, $i+$y_chunk, $debug2);
|
||||
}
|
||||
}
|
||||
|
||||
// for debug:
|
||||
//sendImage($im2);
|
||||
|
||||
ImageFilledRectangle($im,0,0,$width,$height,$bg);
|
||||
// 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 += $rand_func(-1,1);
|
||||
ImageCopy($im, $im2, $i, $y_pos, $i, 0, $x_chunk, $height);
|
||||
|
||||
// for debug:
|
||||
//ImageLine($im,$i+$x_chunk,0,$i+$x_chunk,100,$debug);
|
||||
//ImageLine($im,$i,$y_pos+25,$i+$x_chunk,$y_pos+25,$debug);
|
||||
}
|
||||
|
||||
// for debug:
|
||||
//sendImage($im);
|
||||
|
||||
// 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)
|
||||
myImageBlur($im);
|
||||
|
||||
// for debug:
|
||||
//sendImage($im);
|
||||
|
||||
if($output!="jpg" && $bg_type==0)
|
||||
{
|
||||
// make background transparent
|
||||
ImageColorTransparent($im,$bg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
////// Try to avoid 'free p*rn' style CAPTCHA re-use
|
||||
//////////////////////////////////////////////////////
|
||||
// ('*'ed to stop my site coming up for certain keyword searches on google)
|
||||
|
||||
// can obscure CAPTCHA word in some cases..
|
||||
|
||||
// write site tags 'shining through' the morphed image
|
||||
ImageFilledRectangle($im2,0,0,$width,$height,$bg2);
|
||||
if(is_array($site_tags))
|
||||
{
|
||||
for($i=0 ; $i<sizeof($site_tags) ; $i++)
|
||||
{
|
||||
// ensure tags are centered
|
||||
$tag_width = strlen($site_tags[$i])*6;
|
||||
// write tag is chosen position
|
||||
if($tag_pos==0 || $tag_pos==2)
|
||||
{
|
||||
// write at top
|
||||
ImageString($im2, 2, intval($width/2)-intval($tag_width/2), (10*$i), $site_tags[$i], $site_tag_col2);
|
||||
}
|
||||
if($tag_pos==1 || $tag_pos==2)
|
||||
{
|
||||
// write at bottom
|
||||
ImageString($im2, 2, intval($width/2)-intval($tag_width/2), ($height-34+($i*10)), $site_tags[$i], $site_tag_col2);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImageCopyMerge($im2,$im,0,0,0,0,$width,$height,80);
|
||||
ImageCopy($im,$im2,0,0,0,0,$width,$height);
|
||||
// for debug:
|
||||
//sendImage($im);
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
////// Merge with obfuscated background
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
if($bg_type!=0)
|
||||
{
|
||||
// merge bg image with CAPTCHA image to create smooth background
|
||||
|
||||
// fade bg:
|
||||
if($bg_type!=3)
|
||||
{
|
||||
$temp_im = ImageCreateTrueColor($width,$height);
|
||||
$white = ImageColorAllocate($temp_im,255,255,255);
|
||||
ImageFill($temp_im,0,0,$white);
|
||||
ImageCopyMerge($im3,$temp_im,0,0,0,0,$width,$height,$bg_fade_pct);
|
||||
// for debug:
|
||||
//sendImage($im3);
|
||||
ImageDestroy($temp_im);
|
||||
$c_fade_pct = 50;
|
||||
} else {
|
||||
$c_fade_pct = $bg_fade_pct;
|
||||
}
|
||||
|
||||
// captcha over bg:
|
||||
// might want to not blur if using this method
|
||||
// otherwise leaves white-ish border around each letter
|
||||
if($merge_type==1)
|
||||
{
|
||||
ImageCopyMerge($im3,$im,0,0,0,0,$width,$height,100);
|
||||
ImageCopy($im,$im3,0,0,0,0,$width,$height);
|
||||
} else {
|
||||
// bg over captcha:
|
||||
ImageCopyMerge($im,$im3,0,0,0,0,$width,$height,$c_fade_pct);
|
||||
}
|
||||
}
|
||||
// for debug:
|
||||
//sendImage($im);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
////// Write tags, remove variables and output!
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// tag it
|
||||
// feel free to remove/change
|
||||
// but if it's not essential I'd appreciate you leaving it
|
||||
// after all, I've put a lot of work into this and am giving it away for free
|
||||
// the least you could do is give me credit (or buy me stuff from amazon!)
|
||||
// but I understand that in professional environments, your boss might not like this tag
|
||||
// so that's cool.
|
||||
$tag_str = "freeCap v1.41 - puremango.co.uk";
|
||||
// for debug:
|
||||
//$tag_str = "[".$word."]";
|
||||
|
||||
// ensure tag is right-aligned
|
||||
$tag_width = strlen($tag_str)*6;
|
||||
// write tag
|
||||
ImageString($im, 2, $width-$tag_width, $height-13, $tag_str, $tag_col);
|
||||
|
||||
// unset all sensetive vars
|
||||
// in case someone include()s this file on a shared server
|
||||
// you might think this unneccessary, as it exit()s
|
||||
// but by using register_shutdown_function
|
||||
// on a -very- insecure shared server, they -might- be able to get the word
|
||||
unset($word);
|
||||
// the below aren't really essential, but might aid an OCR attack if discovered.
|
||||
// so we unset them
|
||||
unset($use_dict);
|
||||
unset($dict_location);
|
||||
unset($max_word_length);
|
||||
unset($bg_type);
|
||||
unset($bg_images);
|
||||
unset($merge_type);
|
||||
unset($bg_fade_pct);
|
||||
unset($morph_bg);
|
||||
unset($col_type);
|
||||
unset($max_attempts);
|
||||
unset($font_locations);
|
||||
|
||||
|
||||
// output final image :-)
|
||||
sendImage($im);
|
||||
// (sendImage also destroys all used images)
|
||||
?>
|
||||
1
typo3conf/ext/sr_freecap/Resources/Private/.htaccess
Normal file
1
typo3conf/ext/sr_freecap/Resources/Private/.htaccess
Normal file
@@ -0,0 +1 @@
|
||||
deny from all
|
||||
@@ -0,0 +1,11 @@
|
||||
<f:be.container includeCssFiles="{0: '{f:uri.resource(path:\'StyleSheets/FontMaker.css\')}'}">
|
||||
<div id="typo3-docheader">
|
||||
<div class="typo3-docheader-functions"> </div>
|
||||
<div class="typo3-docheader-buttons"> </div>
|
||||
</div>
|
||||
<div id="typo3-docbody">
|
||||
<div id="typo3-inner-docbody">
|
||||
<div id="typo3-mod-freecap-font-maker"><f:render section="Content" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</f:be.container>
|
||||
@@ -0,0 +1,10 @@
|
||||
{namespace freeCap=SJBR\SrFreecap\ViewHelpers}
|
||||
<f:form.validationResults for="{for}">
|
||||
<f:if condition="{validationResults.flattenedErrors}">
|
||||
<ul class="errors">
|
||||
<f:for each="{validationResults.errors}" as="error">
|
||||
<li><freeCap:translate key="{error.code}">{error.code}</freeCap:translate></li>
|
||||
</f:for>
|
||||
</ul>
|
||||
</f:if>
|
||||
</f:form.validationResults>
|
||||
@@ -0,0 +1,27 @@
|
||||
<f:layout name="Default" />
|
||||
|
||||
<f:section name="Content">
|
||||
<h2>{f:translate(key: 'title-created')}</h2>
|
||||
<fieldset class="sjbr-freecap-font-maker-created">
|
||||
<dl>
|
||||
<dt>
|
||||
<label>{f:translate(key: 'usingFontFile')}</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<strong>{font.ttfFontFileName}</strong>
|
||||
</dd>
|
||||
<dt>
|
||||
<label for="sjbr-freecap-font-maker-characterWidth">{f:translate(key: 'pngImageCreated')}</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<img src="../{font.pngImageFileName}" alt="{f:translate(key: 'pngFontImage')}" />
|
||||
</dd>
|
||||
<dt>
|
||||
<label for="sjbr-freecap-font-maker-characterHeight">{f:translate(key: 'gdFontFileCreated')}</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<strong>{font.gdFontFileName}</strong>
|
||||
</dd>
|
||||
</dl>
|
||||
</fieldset>
|
||||
</f:section>
|
||||
@@ -0,0 +1,61 @@
|
||||
<f:layout name="Default" />
|
||||
|
||||
<f:section name="Content">
|
||||
<h2>{f:translate(key: 'title')}</h2>
|
||||
<f:form method="post" controller="FontMaker" action="create" name="font" object="{font}" class="sjbr-freecap-font-maker">
|
||||
<fieldset>
|
||||
<dl>
|
||||
<dt>
|
||||
<label>{f:translate(key: 'charactersToIncludeInFont')}</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<f:form.radio id="sjbr-freecap-font-maker-charactersIncludedInFont-0" property="charactersIncludedInFont" value="0" /><label for="sjbr-freecap-font-maker-charactersIncludedInFont-0">{f:translate(key: 'numbers-only')}</label>
|
||||
<br />
|
||||
<f:form.radio id="sjbr-freecap-font-maker-charactersIncludedInFont-1" property="charactersIncludedInFont" value="1" /><label for="sjbr-freecap-font-maker-charactersIncludedInFont-1">{f:translate(key: 'ASCII-lowercase-letters')}</label>
|
||||
<br />
|
||||
<f:form.radio id="sjbr-freecap-font-maker-charactersIncludedInFont-2" property="charactersIncludedInFont" value="2" /><label for="sjbr-freecap-font-maker-charactersIncludedInFont-2">{f:translate(key: 'ANSI-extended-ASCII-lowercase-letters')}</label>
|
||||
</dd>
|
||||
<dt>
|
||||
<label for="sjbr-freecap-font-maker-characterWidth">{f:translate(key: 'characterWidth')}</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<f:form.textfield id="sjbr-freecap-font-maker-characterWidth" property="characterWidth" size="5" />
|
||||
<f:render partial="FormErrors" arguments="{for: 'font.characterWidth'}" />
|
||||
</dd>
|
||||
<dt>
|
||||
<label for="sjbr-freecap-font-maker-characterHeight">{f:translate(key: 'characterHeight')}</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<f:form.textfield id="sjbr-freecap-font-maker-characterHeight" property="characterHeight" size="5" />
|
||||
<f:render partial="FormErrors" arguments="{for: 'font.characterHeight'}" />
|
||||
</dd>
|
||||
<dt>
|
||||
<label>{f:translate(key: 'endianness')}</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<f:form.radio id="sjbr-freecap-font-maker-endianness-0" property="endianness" value="0" /><label for="sjbr-freecap-font-maker-endianness-0">{f:translate(key: 'littleEndian')}</label>
|
||||
<br />
|
||||
<f:form.radio id="sjbr-freecap-font-maker-endianness-1" property="endianness" value="1" /><label for="sjbr-freecap-font-maker-endianness-1">{f:translate(key: 'bigEndian')}</label>
|
||||
</dd>
|
||||
<dt>
|
||||
<label for="sjbr-freecap-font-maker-ttfFontFileName">{f:translate(key: 'pathToTTFFile')}</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<f:form.textfield id="sjbr-freecap-font-maker-ttfFontFileName" property="ttfFontFileName" size="50" />
|
||||
<f:render partial="FormErrors" arguments="{for: 'font.ttfFontFileName'}" />
|
||||
</dd>
|
||||
<dt>
|
||||
<label for="sjbr-freecap-font-maker-gdFontFilePrefix">{f:translate(key: 'gdFontFilePrefix')}</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<f:form.textfield id="sjbr-freecap-font-maker-gdFontFilePrefix" property="gdFontFilePrefix" size="25" />
|
||||
</dd>
|
||||
<dt>
|
||||
</dt>
|
||||
<dd>
|
||||
<f:form.submit class="submit" value="{f:translate(key: 'makeFont')}" />
|
||||
</dd>
|
||||
</dl>
|
||||
</fieldset>
|
||||
</f:form>
|
||||
</f:section>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 109 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user