forked from joshirohit100/captcha_after
-
Notifications
You must be signed in to change notification settings - Fork 1
/
captcha_after.module
210 lines (183 loc) · 7.14 KB
/
captcha_after.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
<?php
/**
* @file
* Main module file for the captcha_after module.
*/
use Drupal\captcha\Entity\CaptchaPoint;
use Drupal\Core\Form\FormStateInterface;
/**
* Implements hook_module_implements_alter().
*/
function captcha_after_module_implements_alter(&$implementations, $hook) {
if ($hook == 'form_alter') {
$group = $implementations['captcha_after'];
unset($implementations['captcha_after']);
$implementations['captcha_after'] = $group;
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function captcha_after_form_captcha_point_edit_form_alter(array &$form, FormStateInterface $form_state) {
// Add captcha delay settings element to the captcha_entity.
_captcha_after_delay_attempt_element($form, $form_state);
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function captcha_after_form_captcha_point_add_form_alter(array &$form, FormStateInterface $form_state) {
// Add captcha delay settings element to the captcha_entity.
_captcha_after_delay_attempt_element($form, $form_state);
}
/**
* Adds captcha_after settings to captcha_point entity.
*
* @param array $form
* Form element.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* Form state instance.
*/
function _captcha_after_delay_attempt_element(array &$form, FormStateInterface $form_state) {
/* @var \Drupal\captcha\Entity\CaptchaPoint $captcha_point */
$captcha_point = $form_state->getFormObject()->getEntity();
$form['captcha_after'] = [
'#type' => 'details',
'#title' => t('Captcha After Settings'),
'#description' => t('Captcha after related settings for this captcha point
entity. Global flooding threshold is evaluated first then Host/IP based
flooding.'),
'#open' => FALSE,
];
$form['captcha_after']['captcha_after_global_flooding_threshold'] = [
'#type' => 'number',
'#title' => t('CAPTCHA global flooding threshold'),
'#description' => t('Number of times <strong>ALL</strong> visitors are
allowed to submit a protected form within an hour before starting to
protect form with CAPTCHA. This is useful for protecting against flooding
from multiple IPs. Enter 0 to disable this behaviour.'),
'#default_value' => $captcha_point->getThirdPartySetting('captcha_after', 'captcha_after_global_flooding_threshold') ?: 0,
];
$form['captcha_after']['captcha_after_flooding_threshold'] = [
'#type' => 'number',
'#title' => t('CAPTCHA flooding threshold'),
'#description' => t('Number of times a visitor (based on hostname/IP) is
allowed to submit a protected form in an hour before starting to protect
form with CAPTCHA. This is useful for protecting against repeated (but
valid) submissions. Enter 0 to disable this behaviour.'),
'#default_value' => $captcha_point->getThirdPartySetting('captcha_after', 'captcha_after_flooding_threshold') ?: 0,
];
$form['#entity_builders'][] = 'captcha_after_form_captcha_point_entity_builder';
}
/**
* Entity builder for the captcha point configuration entity.
*/
function captcha_after_form_captcha_point_entity_builder($entity_type, CaptchaPoint $captcha_point, &$form, FormStateInterface $form_state) {
if ($form_state->getValue('captcha_after_flooding_threshold')) {
$captcha_point->setThirdPartySetting('captcha_after', 'captcha_after_flooding_threshold', $form_state->getValue('captcha_after_flooding_threshold'));
}
if ($form_state->getValue('captcha_after_global_flooding_threshold')) {
$captcha_point->setThirdPartySetting('captcha_after', 'captcha_after_global_flooding_threshold', $form_state->getValue('captcha_after_global_flooding_threshold'));
}
}
/**
* Implements hook_form_alter().
*/
function captcha_after_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
$captcha = isset($form['captcha'])?: FALSE;
// If captcha is enabled on the form.
if ($captcha) {
/* @var \Drupal\captcha\Entity\CaptchaPoint $captcha_point */
$captcha_point = \Drupal::entityTypeManager()
->getStorage('captcha_point')
->load($form_id);
// Get captcha_after settings.
$flooding_threshold = $captcha_point->getThirdPartySetting('captcha_after', 'captcha_after_flooding_threshold');
$global_flooding_threshold = $captcha_point->getThirdPartySetting('captcha_after', 'captcha_after_global_flooding_threshold');
// If all thresholds are empty or 0, no need to show the captcha.
if (empty($flooding_threshold) && empty($global_flooding_threshold)) {
return;
}
// Flag to determine hiding the captcha.
$hide_captcha = FALSE;
// Set flood variable.
$flood = $form_state->get('flood') ?: \Drupal::flood();
if (!$form_state->get('flood')) {
$form_state->set('flood', $flood);
}
// Flood events to register.
$flood_events = [];
// If global settings is set on the form.
if (!empty($global_flooding_threshold)) {
// Flood event name.
$flood_event = 'captcha_after_global_flooding_threshold_' . $form['#id'];
// If flood not exceeds threshold.
if ($flood->isAllowed($flood_event, $global_flooding_threshold)) {
// Add to flood event.
$flood_events[] = $flood_event;
// Hide the captcha.
$hide_captcha = TRUE;
}
}
// If Host/IP level threshold is enabled.
if (!empty($flooding_threshold)) {
// Flood event name.
$flood_event = 'captcha_after_flooding_threshold_' . $form['#id'];
// If flood not exceeds threshold.
if ($flood->isAllowed($flood_event, $flooding_threshold)) {
$flood_events[] = $flood_event;
// Hide the captcha.
$hide_captcha = TRUE;
}
else {
$hide_captcha = FALSE;
// If user level flood exceed, no need to then increase global flood.
$flood_events = [];
}
}
// Hide the captcha.
if ($hide_captcha) {
unset($form['captcha']);
}
// Register flood event and handlers.
$form_state->set('flood_events', $flood_events);
$form['#validate'][] = '_captcha_after_form_validate';
$form['#submit'][] = '_captcha_after_form_submit';
}
}
/**
* Form validation handler to fill the flood.
*/
function _captcha_after_form_validate(&$form, FormStateInterface $form_state) {
// If there is any error, then register flood.
if ($form_state->getErrors()) {
// Available flood events.
$flood_events = $form_state->get('flood_events');
// If there is any flood event, register it.
if (!empty($flood_events)) {
// The flood object.
$flood = $form_state->get('flood');
foreach ($flood_events as $flood_event) {
$flood->register($flood_event);
}
}
}
}
/**
* Form submit handler to clear the flood.
*/
function _captcha_after_form_submit(&$form, FormStateInterface $form_state) {
// Available flood events.
$flood_events = $form_state->get('flood_events');
// Clear the flood system.
if (!empty($flood_events)) {
// The flood object.
$flood = $form_state->get('flood');
foreach ($flood_events as $flood_event) {
// Do not clear the global threshold flood.
if (strpos($flood_event, 'captcha_after_global_flooding_threshold_') !== FALSE) {
continue;
}
$flood->clear($flood_event);
}
}
}