-
Notifications
You must be signed in to change notification settings - Fork 395
Feature: Proof of Work captcha #4495
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
crhallberg
wants to merge
31
commits into
vufind-org:dev
Choose a base branch
from
crhallberg:pow-captcha
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 12 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
0b2b78c
start: proof of work captcha feature.
crhallberg b3b6c80
feat: session id used to generate consistent secrets.
crhallberg 6fc0381
fix: alignment of captcha with comment.
crhallberg 356676b
fix: send less information back with form, since we have a better sta…
crhallberg 35a4318
doc: copyright 2
crhallberg 5a6f033
chore: qa-js-and-scss
crhallberg 843c2ea
chore: php-cs-fixer
crhallberg a21c1e2
doc: rename CAPTCHA
crhallberg 1d3336e
Update module/VuFind/src/VuFind/Captcha/PoW.php
crhallberg 5746da2
doc: update copyright
crhallberg 136e3cb
doc: copyright
crhallberg 04fe429
feat: add Altcha as an option.
crhallberg 6b5884f
fix: woke up in the middle of the night in a cold sweat with the abso…
crhallberg 8ff7271
refactor: pass Altcha instance from Factory.
crhallberg 761e780
rm: unused file since vendor supplies WebComponent.
crhallberg c97bfba
fix: remove postinstall.
crhallberg 8dc7d17
doc: add Altcha LICENSE.
crhallberg 62ca158
remove home-grown pow solution.
crhallberg d06cb50
fix: escape challenge JSON.
crhallberg 7f1b88a
Update config/vufind/config.ini
crhallberg 182f5bd
docs: fix parameter types.
crhallberg a9f9003
style: phpcs
crhallberg a358335
Merge branch 'pow-captcha' of https://github.com/crhallberg/vufind in…
crhallberg d6972fa
Merge branch 'dev' into pow-captcha
crhallberg fb11bf4
Merge branch 'dev' into pow-captcha
demiankatz de5dae0
Fix outdated license text.
demiankatz 826c5a9
Handle garbled input data more robustly.
demiankatz 2e485c6
php-cs-fixer
demiankatz 22e93c6
Update module/VuFind/src/VuFind/Captcha/AltchaFactory.php
crhallberg 8723bef
Merge branch 'dev' into pow-captcha
demiankatz e61d683
Style fixes.
demiankatz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * Altcha proof-of-work CAPTCHA. | ||
| * | ||
| * PHP version 8 | ||
| * | ||
| * Copyright (C) Villanova University 2025. | ||
| * | ||
| * This program is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License version 2, | ||
| * as published by the Free Software Foundation. | ||
| * | ||
| * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| * | ||
| * @category VuFind | ||
| * @package CAPTCHA | ||
| * @author Chris Hallberg <challber@villanova.edu> | ||
| * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License | ||
| * @link https://vufind.org Main Page | ||
| */ | ||
|
|
||
| namespace VuFind\Captcha; | ||
|
|
||
| use AltchaOrg\Altcha\Altcha as AltchaController; | ||
|
crhallberg marked this conversation as resolved.
Outdated
|
||
| use AltchaOrg\Altcha\ChallengeOptions; | ||
| use AltchaOrg\Altcha\Hasher\Algorithm; | ||
| use Laminas\Mvc\Controller\Plugin\Params; | ||
|
|
||
| use function intval; | ||
|
|
||
| /** | ||
| * Altcha proof-of-work CAPTCHA. | ||
| * | ||
| * @category VuFind | ||
| * @package CAPTCHA | ||
| * @author Chris Hallberg <challber@villanova.edu> | ||
| * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License | ||
| * @link https://vufind.org/wiki/development Wiki | ||
| */ | ||
| class Altcha extends AbstractBase | ||
| { | ||
| /** | ||
| * Constructor | ||
| * | ||
| * @param string $hmacKey Required HMAC key for challenge calculation and solution verification. | ||
| * | ||
| * @param Algorithm $algorithm Hashing algorithm to use (`SHA-1`, `SHA-256`, `SHA-512`, default: `SHA-256`). | ||
| * @param int $maxNumber Maximum number for the random number generator (default: 1,000,000) | ||
| * @param null|\DateTimeInterface $expires Optional expiration time for the challenge. | ||
| * @param ChallengeParams $params Optional URL-encoded query parameters. | ||
| * @param int<1, max> $saltLength Length of the random salt (default: 12 bytes). | ||
| */ | ||
| public function __construct( | ||
| protected string $hmacKey, | ||
| // Options for creation of a new challenge | ||
| protected Algorithm $algorithm = Algorithm::SHA256, | ||
| protected int $maxNumber = AltchaController::DEFAULT_MAX_NUMBER, | ||
| protected ?\DateTimeInterface $expires = null, | ||
| protected array $params = [], | ||
| protected int $saltLength = AltchaController::DEFAULT_SALT_LENGTH, | ||
| ) { | ||
| } | ||
|
|
||
| /** | ||
| * Get list of URLs with JS dependencies to load for the active CAPTCHA type. | ||
| * | ||
| * @return array | ||
| */ | ||
| public function getJsIncludes(): array | ||
| { | ||
| return ['vendor/altcha.js', 'vendor/altcha-i18n.js']; | ||
| } | ||
|
|
||
| /** | ||
| * Generate challenge | ||
| * | ||
| * @return Challenge | ||
| */ | ||
| public function getChallenge() | ||
| { | ||
| $altcha = new AltchaController($this->hmacKey); | ||
|
crhallberg marked this conversation as resolved.
Outdated
|
||
|
|
||
| $options = new ChallengeOptions( | ||
| algorithm: $this->algorithm, | ||
| maxNumber: $this->maxNumber, | ||
| expires: $this->expires, | ||
| params: $this->params, | ||
| saltLength: $this->saltLength, | ||
| ); | ||
|
|
||
| return json_encode($altcha->createChallenge($options)); | ||
| } | ||
|
|
||
| /** | ||
| * Pull the captcha field from controller params and check them for accuracy | ||
| * We pull from the form in case config changed since challenge was sent | ||
| * | ||
| * @param Params $params Controller params | ||
| * | ||
| * @return bool | ||
| */ | ||
| public function verify(Params $params): bool | ||
| { | ||
| $encoded = $params->fromPost('altcha', null); | ||
| $json = base64_decode($encoded); | ||
| $payload = json_decode($json, true); | ||
|
|
||
| $altcha = new AltchaController($this->hmacKey); | ||
| return $altcha->verifySolution($payload, checkExpires: true); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,106 @@ | ||||||||||
| <?php | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Factory for Altcha proof-of-work CAPTCHA module. | ||||||||||
| * | ||||||||||
| * PHP version 8 | ||||||||||
| * | ||||||||||
| * Copyright (C) Villanova University 2025. | ||||||||||
| * | ||||||||||
| * This program is free software; you can redistribute it and/or modify | ||||||||||
| * it under the terms of the GNU General Public License version 2, | ||||||||||
| * as published by the Free Software Foundation. | ||||||||||
| * | ||||||||||
| * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||||||||
| * | ||||||||||
| * @category VuFind | ||||||||||
| * @package CAPTCHA | ||||||||||
| * @author Chris Hallberg <challber@villanova.edu> | ||||||||||
| * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License | ||||||||||
| * @link https://vufind.org/wiki/development Wiki | ||||||||||
| */ | ||||||||||
|
|
||||||||||
| namespace VuFind\Captcha; | ||||||||||
|
|
||||||||||
| use AltchaOrg\Altcha\Hasher\Algorithm; | ||||||||||
| use Laminas\ServiceManager\Exception\ServiceNotCreatedException; | ||||||||||
| use Laminas\ServiceManager\Exception\ServiceNotFoundException; | ||||||||||
| use Laminas\ServiceManager\Factory\FactoryInterface; | ||||||||||
| use Psr\Container\ContainerExceptionInterface as ContainerException; | ||||||||||
| use Psr\Container\ContainerInterface; | ||||||||||
|
|
||||||||||
| use function in_array; | ||||||||||
| use function intval; | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Altcha proof-of-work CAPTCHA factory. | ||||||||||
| * | ||||||||||
| * @category VuFind | ||||||||||
| * @package CAPTCHA | ||||||||||
| * @author Chris Hallberg <challber@villanova.edu> | ||||||||||
| * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License | ||||||||||
| * @link https://vufind.org/wiki/development Wiki | ||||||||||
| */ | ||||||||||
| class AltchaFactory implements FactoryInterface | ||||||||||
| { | ||||||||||
| /** | ||||||||||
| * Create an object | ||||||||||
| * | ||||||||||
| * @param ContainerInterface $container Service manager | ||||||||||
| * @param string $requestedName Service being created | ||||||||||
| * @param null|array $options Extra options (optional) | ||||||||||
| * | ||||||||||
| * @return object | ||||||||||
| * | ||||||||||
| * @throws ServiceNotFoundException if unable to resolve the service. | ||||||||||
| * @throws ServiceNotCreatedException if an exception is raised when | ||||||||||
| * creating a service. | ||||||||||
| * @throws ContainerException&\Throwable if any other error occurs | ||||||||||
| */ | ||||||||||
| public function __invoke( | ||||||||||
| ContainerInterface $container, | ||||||||||
| $requestedName, | ||||||||||
| ?array $options = null | ||||||||||
| ) { | ||||||||||
| if (!empty($options)) { | ||||||||||
| throw new \Exception('Unexpected options passed to factory.'); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| $config = $container | ||||||||||
| ->get(\VuFind\Config\PluginManager::class) | ||||||||||
| ->get('config'); | ||||||||||
|
Comment on lines
+74
to
+75
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. \VuFind\Config\PluginManager has been deprecated. This should become:
Suggested change
|
||||||||||
|
|
||||||||||
| $secret = $config->Captcha->altcha_secret ?? null; | ||||||||||
|
|
||||||||||
| if (empty($secret)) { | ||||||||||
| throw new \Exception('Secret key needed for Altcha. See config.ini.'); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| $algorithm = Algorithm::from($config->Captcha->altcha_algorithm ?? 'SHA-256'); | ||||||||||
|
crhallberg marked this conversation as resolved.
Outdated
|
||||||||||
| $max_number = $config->Captcha->altcha_max_number ?? 100000; | ||||||||||
| $salt_len = $config->Captcha->altcha_salt_len ?? 12; | ||||||||||
| $expires_interval = $config->Captcha->altcha_expires_interval ?? null; | ||||||||||
| $params = $config->Captcha->altcha_params ?? []; | ||||||||||
|
|
||||||||||
| $expires = !empty($expires_interval) | ||||||||||
| ? (new \DateTimeImmutable())->add(new \DateInterval($expires_interval)) | ||||||||||
| : null; | ||||||||||
|
|
||||||||||
| return new $requestedName( | ||||||||||
| $secret, | ||||||||||
| // challenge options | ||||||||||
| $algorithm, | ||||||||||
| $max_number, | ||||||||||
| $expires, | ||||||||||
| $params, | ||||||||||
| $salt_len, | ||||||||||
| ); | ||||||||||
| } | ||||||||||
| } | ||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.