Skip to content
Snippets Groups Projects
Commit c014078f authored by Michael Lee's avatar Michael Lee
Browse files

Merge branch 'captcha' into lee5151

parents 8e65c92e 855bb576
No related branches found
No related tags found
No related merge requests found
Showing
with 296 additions and 130 deletions
......@@ -2392,26 +2392,26 @@
},
{
"name": "drupal/captcha",
"version": "1.2.0",
"version": "1.7.0",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/captcha.git",
"reference": "8.x-1.2"
"reference": "8.x-1.7"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/captcha-8.x-1.2.zip",
"reference": "8.x-1.2",
"shasum": "e35a2ce42b652f833d140f7571d1eef0e06b0edc"
"url": "https://ftp.drupal.org/files/projects/captcha-8.x-1.7.zip",
"reference": "8.x-1.7",
"shasum": "030c500b8b20b564b58be5ed84735eec9ba7f51a"
},
"require": {
"drupal/core": "^8.8 || ^9"
"drupal/core": ">=8.9 <11"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "8.x-1.2",
"datestamp": "1619673374",
"version": "8.x-1.7",
"datestamp": "1668434204",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
......@@ -2426,10 +2426,22 @@
"GPL-2.0-or-later"
],
"authors": [
{
"name": "Anybody",
"homepage": "https://www.drupal.org/user/291091"
},
{
"name": "elachlan",
"homepage": "https://www.drupal.org/user/1021502"
},
{
"name": "gisle",
"homepage": "https://www.drupal.org/user/409554"
},
{
"name": "Grevil",
"homepage": "https://www.drupal.org/user/3668491"
},
{
"name": "japerry",
"homepage": "https://www.drupal.org/user/45640"
......@@ -2450,6 +2462,10 @@
"name": "soxofaan",
"homepage": "https://www.drupal.org/user/41478"
},
{
"name": "thomas.frobieter",
"homepage": "https://www.drupal.org/user/409335"
},
{
"name": "wundo",
"homepage": "https://www.drupal.org/user/25523"
......
......@@ -2468,27 +2468,27 @@
},
{
"name": "drupal/captcha",
"version": "1.2.0",
"version_normalized": "1.2.0.0",
"version": "1.7.0",
"version_normalized": "1.7.0.0",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/captcha.git",
"reference": "8.x-1.2"
"reference": "8.x-1.7"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/captcha-8.x-1.2.zip",
"reference": "8.x-1.2",
"shasum": "e35a2ce42b652f833d140f7571d1eef0e06b0edc"
"url": "https://ftp.drupal.org/files/projects/captcha-8.x-1.7.zip",
"reference": "8.x-1.7",
"shasum": "030c500b8b20b564b58be5ed84735eec9ba7f51a"
},
"require": {
"drupal/core": "^8.8 || ^9"
"drupal/core": ">=8.9 <11"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "8.x-1.2",
"datestamp": "1619673374",
"version": "8.x-1.7",
"datestamp": "1668434204",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
......@@ -2505,13 +2505,21 @@
],
"authors": [
{
"name": "RobLoach",
"homepage": "https://www.drupal.org/user/61114"
"name": "Anybody",
"homepage": "https://www.drupal.org/user/291091"
},
{
"name": "elachlan",
"homepage": "https://www.drupal.org/user/1021502"
},
{
"name": "gisle",
"homepage": "https://www.drupal.org/user/409554"
},
{
"name": "Grevil",
"homepage": "https://www.drupal.org/user/3668491"
},
{
"name": "japerry",
"homepage": "https://www.drupal.org/user/45640"
......@@ -2524,10 +2532,18 @@
"name": "podarok",
"homepage": "https://www.drupal.org/user/116002"
},
{
"name": "RobLoach",
"homepage": "https://www.drupal.org/user/61114"
},
{
"name": "soxofaan",
"homepage": "https://www.drupal.org/user/41478"
},
{
"name": "thomas.frobieter",
"homepage": "https://www.drupal.org/user/409335"
},
{
"name": "wundo",
"homepage": "https://www.drupal.org/user/25523"
......
......@@ -386,9 +386,9 @@
'dev_requirement' => false,
),
'drupal/captcha' => array(
'pretty_version' => '1.2.0',
'version' => '1.2.0.0',
'reference' => '8.x-1.2',
'pretty_version' => '1.7.0',
'version' => '1.7.0.0',
'reference' => '8.x-1.7',
'type' => 'drupal-module',
'install_path' => __DIR__ . '/../../web/modules/captcha',
'aliases' => array(),
......
services:
php:
image: q0rban/tugboat-drupal:9.0
default: true
http: false
depends: mysql
commands:
update: |
set -eux
# Check out a branch using the unique Tugboat ID for this repository, to
# ensure we don't clobber an existing branch.
git checkout -b $TUGBOAT_REPO_ID
# Composer is hungry. You need a Tugboat project with a pretty sizeable
# chunk of memory.
export COMPOSER_MEMORY_LIMIT=-1
# This is an environment variable we added in the Dockerfile that
# provides the path to Drupal composer root (not the web root).
cd $DRUPAL_COMPOSER_ROOT
# We configure the Drupal project to use the checkout of the module as a
# Composer package repository.
composer config repositories.tugboat vcs $TUGBOAT_ROOT
# Now we can require this module, specifing the branch name we created
# above that uses the $TUGBOAT_REPO_ID environment variable.
composer require drupal/captcha:dev-$TUGBOAT_REPO_ID
# Install Drupal on the site.
vendor/bin/drush \
--yes \
--db-url=mysql://tugboat:tugboat@mysql:3306/tugboat \
--site-name="Live preview for ${TUGBOAT_PREVIEW_NAME}" \
--account-pass=admin \
site:install standard
# Set up the files directory permissions.
mkdir -p $DRUPAL_DOCROOT/sites/default/files
chgrp -R www-data $DRUPAL_DOCROOT/sites/default/files
chmod 2775 $DRUPAL_DOCROOT/sites/default/files
chmod -R g+w $DRUPAL_DOCROOT/sites/default/files
# Enable the module.
vendor/bin/drush --yes pm:enable captcha
build: |
set -eux
# Delete and re-check out this branch in case this is built from a Base Preview.
git branch -D $TUGBOAT_REPO_ID && git checkout -b $TUGBOAT_REPO_ID || true
export COMPOSER_MEMORY_LIMIT=-1
cd $DRUPAL_COMPOSER_ROOT
composer install --optimize-autoloader
# Update this module, including all dependencies.
composer update drupal/captcha --with-all-dependencies
vendor/bin/drush --yes updb
vendor/bin/drush cache:rebuild
mysql:
image: tugboatqa/mariadb
......@@ -73,31 +73,6 @@ function foo_captcha_captcha($op, $captcha_type = '') {
}
}
/**
* Implements hook_menu().
*
* Validation of the answer against the solution and other stuff is done by the
* base CAPTCHA module.
* === Recommended: hook_menu($may_cache) ===
* More advanced CAPTCHA modules probably want some configuration page.
* To integrate nicely with the base CAPTCHA module you should offer your
* configuration page as a MENU_LOCAL_TASK menu entry under
* 'admin/config/people/captcha/'.
* For our simple foo CAPTCHA module this would mean:
*/
function foo_captcha_menu($may_cache) {
$items = [];
if ($may_cache) {
$items['admin/config/people/captcha/foo_captcha'] = [
'title' => t('Foo CAPTCHA'),
'page callback' => 'drupal_get_form',
'page arguments' => ['foo_captcha_settings_form'],
'type' => MENU_LOCAL_TASK,
];
}
return $items;
}
/**
* Implements hook_help().
*
......
captcha.settings:
title: 'CAPTCHA'
base_route_name: captcha_settings
names:
- captcha.settings
......@@ -8,6 +8,7 @@
use Drupal\captcha\Entity\CaptchaPoint;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Render\Element;
use Drupal\captcha\Constants\CaptchaConstants;
/**
* Helper function for adding/updating a CAPTCHA point.
......@@ -23,7 +24,7 @@
* and $captcha_type->captcha_type.
*/
function captcha_set_form_id_setting($form_id, $captcha_type) {
/* @var Drupal\captcha\Entity\CaptchaPoint $captcha_point */
/** @var Drupal\captcha\Entity\CaptchaPoint $captcha_point */
$captcha_point = CaptchaPoint::load($form_id);
if ($captcha_point) {
......@@ -55,7 +56,7 @@ function captcha_set_form_id_setting($form_id, $captcha_type) {
* form 'captcha/Math'.
*/
function captcha_get_form_id_setting($form_id, $symbolic = FALSE) {
/* @var CaptchaPoint $captchaPoint */
/** @var \Drupal\captcha\Entity\CaptchaPoint $captchaPoint */
$captcha_point = CaptchaPoint::load($form_id);
if ($symbolic) {
......@@ -76,7 +77,7 @@ function captcha_get_form_id_setting($form_id, $symbolic = FALSE) {
* @return string
* The session ID of the new CAPTCHA session.
*/
function _captcha_generate_captcha_session($form_id = NULL, $status = CAPTCHA_STATUS_UNSOLVED) {
function _captcha_generate_captcha_session($form_id = NULL, $status = CaptchaConstants::CAPTCHA_STATUS_UNSOLVED) {
$user = \Drupal::currentUser();
// Initialize solution with random data.
......@@ -129,7 +130,7 @@ function _captcha_required_for_user($captcha_sid, $form_id) {
->get('persistence');
// First check: should we always add a CAPTCHA?
if ($captcha_persistence == CAPTCHA_PERSISTENCE_SHOW_ALWAYS) {
if ($captcha_persistence == CaptchaConstants::CAPTCHA_PERSISTENCE_SHOW_ALWAYS) {
return TRUE;
}
......@@ -143,22 +144,22 @@ function _captcha_required_for_user($captcha_sid, $form_id) {
// Second check: if the current session is already
// solved: omit further CAPTCHAs.
if ($captcha_session_status == CAPTCHA_STATUS_SOLVED) {
if ($captcha_session_status == CaptchaConstants::CAPTCHA_STATUS_SOLVED) {
return FALSE;
}
// Third check: look at the persistence level
// (per form instance, per form or per user).
if ($captcha_persistence == CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE) {
if ($captcha_persistence == CaptchaConstants::CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE) {
return TRUE;
}
else {
$captcha_success_form_ids = isset($_SESSION['captcha_success_form_ids']) ? (array) ($_SESSION['captcha_success_form_ids']) : [];
switch ($captcha_persistence) {
case CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL:
case CaptchaConstants::CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL:
return (count($captcha_success_form_ids) == 0);
case CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE:
case CaptchaConstants::CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE:
return !isset($captcha_success_form_ids[$form_id]);
}
}
......@@ -261,7 +262,7 @@ function _captcha_get_captcha_placement($form_id, $form) {
$buttons = _captcha_search_buttons($form);
if (count($buttons)) {
// Pick first button.
// TODO: make this more sofisticated? Use cases needed.
// @todo make this more sofisticated? Use cases needed.
$placement = (isset($buttons[count($buttons) - 1])) ? $buttons[count($buttons) - 1] : $buttons[0];
}
else {
......@@ -299,7 +300,7 @@ function _captcha_search_buttons(array $form) {
foreach (Element::children($form, FALSE) as $key) {
// Look for submit or button type elements.
if (isset($form[$key]['#type']) && ($form[$key]['#type'] == 'submit' || $form[$key]['#type'] == 'button')) {
$weight = isset($form[$key]['#weight']) ? $form[$key]['#weight'] : NULL;
$weight = $form[$key]['#weight'] ?? NULL;
$buttons[] = [
'path' => [],
'key' => $key,
......
......@@ -2,13 +2,10 @@ name: CAPTCHA
type: module
description: Provides the CAPTCHA API for adding challenges to arbitrary forms.
package: Spam control
core_version_requirement: ^8.8 || ^9
core_version_requirement: '>=8.9 <11'
configure: captcha_settings
dependencies:
- drupal:node
# Information added by Drupal.org packaging script on 2021-04-29
version: '8.x-1.2'
# Information added by Drupal.org packaging script on 2022-11-14
version: '8.x-1.7'
project: 'captcha'
datestamp: 1619673377
datestamp: 1668434206
......@@ -110,17 +110,20 @@ function captcha_requirements($phase) {
*/
function captcha_install() {
if (!\Drupal::service('config.installer')->isSyncing()) {
if (!\Drupal::service('config.installer')->isSyncing() && \Drupal::moduleHandler()->moduleExists('node')) {
$form_ids = [];
$label = [];
// Add form_ids of all currently known node types too.
foreach (node_type_get_names() as $type => $name) {
$form_ids[] = 'node_' . $type . '_form';
$label[] = 'node_' . $type . '_form';
}
$captcha_storage = \Drupal::entityTypeManager()
->getStorage('captcha_point');
foreach ($form_ids as $form_id) {
foreach ($form_ids as $index => $form_id) {
$values = [
'label' => $label[$index],
'formId' => $form_id,
'captchaType' => 'default',
'status' => FALSE,
......@@ -130,3 +133,36 @@ function captcha_install() {
}
}
/**
* Implements hook_update_N().
*/
function captcha_update_8901(&$sandbox) {
$entityType = \Drupal::entityTypeManager()
->getDefinition('captcha_point');
if ($entityType) {
\Drupal::entityDefinitionUpdateManager()
->installEntityType($entityType);
}
}
/**
* Implements hook_update_N().
*/
function captcha_update_8902(&$sandbox) {
$query = \Drupal::entityQuery('captcha_point');
$query->notExists('label');
$entity_ids = $query->execute();
if (!empty($entity_ids) && is_array($entity_ids)) {
foreach ($entity_ids as $entity_id) {
$captcha_point_id = $entity_id;
$captcha_point = \Drupal::entityTypeManager()
->getStorage('captcha_point')
->load($captcha_point_id);
$captcha_point->set('label', $captcha_point->getFormId());
$captcha_point->save();
}
}
}
captcha_point.add:
route_name: 'captcha_point.add'
title: 'Add captcha point'
title: 'Add Captcha Point'
appears_on:
- captcha_point.list
......@@ -10,5 +10,5 @@ captcha_examples:
captcha_points.list:
route_name: captcha_point.list
title: 'Form settings'
title: 'Captcha Points'
base_route: captcha_settings
......@@ -20,35 +20,7 @@
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\Core\Site\Settings;
/**
* Constants for CAPTCHA persistence.
*
* TODO: change these integers to strings because the CAPTCHA settings
* form saves them as strings in the variables table anyway?
*/
// @TODO: move all constants to some class.
// Always add a CAPTCHA (even on every page of a multipage workflow).
define('CAPTCHA_PERSISTENCE_SHOW_ALWAYS', 0);
// Only one CAPTCHA has to be solved per form instance/multi-step workflow.
define('CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE', 1);
// Once the user answered correctly for a CAPTCHA on a certain form type,
// no more CAPTCHAs will be offered anymore for that form.
define('CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE', 2);
// Once the user answered correctly for a CAPTCHA on the site,
// no more CAPTCHAs will be offered anymore.
define('CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL', 3);
define('CAPTCHA_STATUS_UNSOLVED', 0);
define('CAPTCHA_STATUS_SOLVED', 1);
define('CAPTCHA_STATUS_EXAMPLE', 2);
define('CAPTCHA_DEFAULT_VALIDATION_CASE_SENSITIVE', 0);
define('CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE', 1);
// Default captcha field access.
define('CAPTCHA_FIELD_DEFAULT_ACCESS', 1);
use Drupal\captcha\Constants\CaptchaConstants;
/**
* Implements hook_help().
......@@ -60,7 +32,7 @@ function captcha_help($route_name, RouteMatchInterface $route_match) {
$output .= '<p>' . t('"CAPTCHA" is an acronym for "Completely Automated Public Turing test to tell Computers and Humans Apart". It is typically a challenge-response test to determine whether the user is human. The CAPTCHA module is a tool to fight automated submission by malicious users (spamming) of for example comments forms, user registration forms, guestbook forms, etc. You can extend the desired forms with an additional challenge, which should be easy for a human to solve correctly, but hard enough to keep automated scripts and spam bots out.') . '</p>';
$output .= '<p>' . t('Note that the CAPTCHA module interacts with page caching (see <a href=":performancesettings">performance settings</a>). Because the challenge should be unique for each generated form, the caching of the page it appears on is prevented. Make sure that these forms do not appear on too many pages or you will lose much caching efficiency. For example, if you put a CAPTCHA on the user login block, which typically appears on each page for anonymous visitors, caching will practically be disabled. The comment submission forms are another example. In this case you should set the <em>Location of comment submission form</em> to <em>Display on separate page</em> in the comment settings of the relevant <a href=":contenttypes">content types</a> for better caching efficiency.', [
':performancesettings' => Url::fromRoute('system.performance_settings')->toString(),
':contenttypes' => Url::fromRoute('entity.node_type.collection')->toString(),
':contenttypes' => \Drupal::moduleHandler()->moduleExists('node') ? Url::fromRoute('entity.node_type.collection')->toString() : '#',
]) . '</p>';
$output .= '<p>' . t('CAPTCHA is a trademark of Carnegie Mellon University.') . '</p>';
return ['#markup' => $output];
......@@ -94,11 +66,12 @@ function captcha_point_load($id) {
* Implements hook_theme().
*/
function captcha_theme() {
$path = \Drupal::service('extension.list.module')->getPath('captcha');
return [
'captcha' => [
'render element' => 'element',
'template' => 'captcha',
'path' => drupal_get_path('module', 'captcha') . '/templates',
'path' => $path . '/templates',
],
];
}
......@@ -165,7 +138,7 @@ function captcha_form_alter(array &$form, FormStateInterface $form_state, $form_
$captchaService = \Drupal::service('captcha.helper');
// Visitor does not have permission to skip CAPTCHAs.
module_load_include('inc', 'captcha');
\Drupal::moduleHandler()->loadInclude('captcha', 'inc');
if (!$account->hasPermission('skip CAPTCHA')) {
$query = \Drupal::entityQuery('captcha_point');
$query->condition('label', $form_id);
......@@ -180,7 +153,7 @@ function captcha_form_alter(array &$form, FormStateInterface $form_state, $form_
if (!empty($entity_ids) && is_array($entity_ids)) {
$captcha_point_id = array_pop($entity_ids);
/* @var CaptchaPoint $captcha_point */
/** @var \Drupal\captcha\Entity\CaptchaPoint $captcha_point */
$captcha_point = \Drupal::entityTypeManager()
->getStorage('captcha_point')
->load($captcha_point_id);
......@@ -209,21 +182,31 @@ function captcha_form_alter(array &$form, FormStateInterface $form_state, $form_
}
if (!empty($captcha_point) && $captcha_point->status()) {
// Build CAPTCHA form element.
$captcha_element = [
'#type' => 'captcha',
'#captcha_type' => $captcha_point->getCaptchaType(),
];
// Add a CAPTCHA description if required.
if ($config->get('add_captcha_description')) {
$captcha_element['#description'] = _captcha_get_description();
// Checking if user's ip is whitelisted.
if (captcha_whitelist_ip_whitelisted()) {
// If form is setup to have captcha, but user's ip is whitelisted, then
// we still have to disable form caching to prevent showing cached form
// for users with not whitelisted ips.
$form['#cache'] = ['max-age' => 0];
\Drupal::service('page_cache_kill_switch')->trigger();
}
else {
// Build CAPTCHA form element.
$captcha_element = [
'#type' => 'captcha',
'#captcha_type' => $captcha_point->getCaptchaType(),
];
// Get placement in form and insert in form.
$captcha_placement = _captcha_get_captcha_placement($form_id, $form);
$captchaService->insertCaptchaElement($form, $captcha_placement, $captcha_element);
// Add a CAPTCHA description if required.
if ($config->get('add_captcha_description')) {
$captcha_element['#description'] = _captcha_get_description();
}
// Get placement in form and insert in form.
if ($captcha_placement = _captcha_get_captcha_placement($form_id, $form)) {
$captchaService->insertCaptchaElement($form, $captcha_placement, $captcha_element);
}
}
}
}
elseif ($config->get('administration_mode') && $account->hasPermission('administer CAPTCHA settings')
......@@ -231,7 +214,7 @@ function captcha_form_alter(array &$form, FormStateInterface $form_state, $form_
->isAdminRoute() || $config->get('allow_on_admin_pages'))
) {
// Add CAPTCHA administration tools.
/* @var \Drupal\captcha\Entity\CaptchaPoint $captcha_point */
/** @var \Drupal\captcha\Entity\CaptchaPoint $captcha_point */
$captcha_point = CaptchaPoint::load($form_id);
// For administrators: show CAPTCHA info and offer link to configure it.
......@@ -394,7 +377,7 @@ function captcha_validate_case_insensitive_ignore_spaces($solution, $response) {
* if the values could not be found, e.g. for a fresh form).
*/
function _captcha_get_posted_captcha_info(array $element, FormStateInterface $form_state, $this_form_id) {
if ($form_state->isSubmitted() && $form_state->has('captcha_info')) {
if ($form_state->has('captcha_info')) {
// We are handling (or rebuilding) an already submitted form,
// so we already determined the posted form ID and CAPTCHA session ID
// for this form (from before submitting). Reuse this info.
......@@ -478,8 +461,8 @@ function captcha_validate($element, FormStateInterface &$form_state) {
// Get CAPTCHA response.
$captcha_response = $form_state->getValue('captcha_response');
// Get CAPTCHA session from CAPTCHA info
// TODO: is this correct in all cases: see comments in previous revisions?
// Get CAPTCHA session from CAPTCHA info.
// @todo is this correct in all cases: see comments in previous revisions?
$csid = $captcha_info['captcha_sid'];
// Bypass captcha validation if access attribute value is false.
......@@ -555,8 +538,8 @@ function captcha_validate($element, FormStateInterface &$form_state) {
if (in_array($captcha_persistence,
[
CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL,
CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE,
CaptchaConstants::CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL,
CaptchaConstants::CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE,
])) {
// Only save the success in $_SESSION if it is actually needed for
// further validation in _captcha_required_for_user(). Setting
......@@ -567,7 +550,7 @@ function captcha_validate($element, FormStateInterface &$form_state) {
// Record success.
\Drupal::database()->update('captcha_sessions')
->condition('csid', $csid)
->fields(['status' => CAPTCHA_STATUS_SOLVED])
->fields(['status' => CaptchaConstants::CAPTCHA_STATUS_SOLVED])
->expression('attempts', 'attempts + 1')
->execute();
}
......@@ -606,7 +589,7 @@ function captcha_validate($element, FormStateInterface &$form_state) {
// rebuilds for re-use attacks during element processing so this should be
// rare if it ever happens.
$form_state->setErrorByName('captcha', t('CAPTCHA validation error: unknown CAPTCHA session ID. Contact the site administrator if this problem persists.'));
\Drupal::logger('CAPTCHA')->error(
\Drupal::logger('CAPTCHA')->warning(
'CAPTCHA validation error: unknown CAPTCHA session ID (%csid).',
['%csid' => var_export($csid, TRUE)]);
}
......@@ -674,7 +657,7 @@ function captcha_captcha($op, $captcha_type = '') {
// This challenge is not visible through the administrative interface
// as it is not listed in captcha_captcha('list'),
// but it is meant for debugging and testing purposes.
// TODO for Drupal 7 version: This should be done with a mock module,
// @todo for Drupal 7 version: This should be done with a mock module,
// but Drupal 6 does not support this (mock modules can not be hidden).
$result = [
'solution' => 'Test 123',
......@@ -693,3 +676,78 @@ function captcha_captcha($op, $captcha_type = '') {
break;
}
}
/**
* Parse values of whitelist ip addresses and ranges.
*
* @param string $whitelist_ips_value
* Contains list of ip addresses and ranges set one per line.
*
* @return array
* Array of parsed ip addresses and ranges.
*/
function captcha_whitelist_ips_parse_values($whitelist_ips_value) {
$whitelist_ips = [
CaptchaConstants::CAPTCHA_WHITELIST_IP_RANGE => [],
CaptchaConstants::CAPTCHA_WHITELIST_IP_ADDRESS => [],
];
// Ensure the IPs value is trimmed before moving onward.
$whitelist_ips_value = trim($whitelist_ips_value ?? "");
if (empty($whitelist_ips_value)) {
return $whitelist_ips;
}
$value_rows = explode("\n", $whitelist_ips_value);
foreach ($value_rows as $value_row) {
$value_row = trim($value_row);
if (strpos($value_row, '-') !== FALSE) {
$whitelist_ips[CaptchaConstants::CAPTCHA_WHITELIST_IP_RANGE][] = $value_row;
}
else {
$whitelist_ips[CaptchaConstants::CAPTCHA_WHITELIST_IP_ADDRESS][] = $value_row;
}
}
return $whitelist_ips;
}
/**
* Check if ip address is whitelisted.
*
* @param string $ip_address
* Optional. IP address to be checked if it is in whitelist. If no ip value
* provided user's current ip will be used to be verified.
*
* @return bool
* TRUE if requested IP address is whitelisted, FALSE if it is not.
*/
function captcha_whitelist_ip_whitelisted($ip_address = '') {
if (empty($ip_address)) {
$ip_address = Drupal::request()->getClientIp();
}
$config = \Drupal::config('captcha.settings');
$whitelist_ips_value = $config->get('whitelist_ips');
$whitelist_ips = captcha_whitelist_ips_parse_values($whitelist_ips_value);
if (in_array($ip_address, $whitelist_ips[CaptchaConstants::CAPTCHA_WHITELIST_IP_ADDRESS])) {
return TRUE;
}
elseif (empty($whitelist_ips[CaptchaConstants::CAPTCHA_WHITELIST_IP_RANGE])) {
return FALSE;
}
foreach ($whitelist_ips[CaptchaConstants::CAPTCHA_WHITELIST_IP_RANGE] as $ip_range) {
[$ip_lower, $ip_upper] = explode('-', $ip_range, 2);
$ip_lower_dec = (float) sprintf("%u", ip2long($ip_lower));
$ip_upper_dec = (float) sprintf("%u", ip2long($ip_upper));
$ip_address_dec = (float) sprintf("%u", ip2long($ip_address));
if (($ip_address_dec >= $ip_lower_dec) && ($ip_address_dec <= $ip_upper_dec)) {
return TRUE;
}
}
return FALSE;
}
<?php
/**
* @file
* Captcha updates once other modules have made their own updates.
*/
/**
* Ensure the container cache is cleared.
*/
function captcha_post_update_refresh_captcha_helper_service() {
drupal_flush_all_caches();
}
......@@ -7,3 +7,4 @@ services:
captcha.helper:
class: Drupal\captcha\Service\CaptchaService
arguments: ['@module_handler']
......@@ -9,9 +9,6 @@
"issues": "https://www.drupal.org/project/issues/captcha",
"source": "https://git.drupalcode.org/project/captcha"
},
"require": {
"drupal/core": "^8.8 || ^9"
},
"extra": {
"branch-alias": {
"dev-8.x-1.x": "1.x-dev"
......
......@@ -3,4 +3,4 @@ status: false
dependencies: { }
formId: contact_message_feedback_form
captchaType: default
label: null
label: contact_message_feedback_form
......@@ -3,4 +3,4 @@ status: false
dependencies: { }
formId: contact_message_personal_form
captchaType: default
label: null
label: contact_message_personal_form
......@@ -3,4 +3,4 @@ status: false
dependencies: { }
formId: user_login_form
captchaType: default
label: null
label: user_login_form
......@@ -3,4 +3,4 @@ status: false
dependencies: { }
formId: user_pass
captchaType: default
label: null
label: user_pass
......@@ -3,4 +3,4 @@ status: false
dependencies: { }
formId: user_register_form
captchaType: default
label: null
label: user_register_form
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment