From 1865d8c1381688426a3271a3c50eb1a8c6731c8d Mon Sep 17 00:00:00 2001 From: Joe Corall Date: Tue, 29 Oct 2024 07:41:00 -0400 Subject: [PATCH] Issue #3483186: Add some metrics --- config/install/turnstile_protect.settings.yml | 1 + config/schema/turnstile_protect.schema.yml | 3 + src/Form/Settings.php | 8 +++ turnstile_protect.install | 55 +++++++++++++++++++ turnstile_protect.module | 27 +++++++++ 5 files changed, 94 insertions(+) create mode 100644 turnstile_protect.install diff --git a/config/install/turnstile_protect.settings.yml b/config/install/turnstile_protect.settings.yml index 0a3c17f..ea2276a 100644 --- a/config/install/turnstile_protect.settings.yml +++ b/config/install/turnstile_protect.settings.yml @@ -20,3 +20,4 @@ rate_limit: true window: 86400 threshold: 20 max_challenges: 5 +history_enabled: false diff --git a/config/schema/turnstile_protect.schema.yml b/config/schema/turnstile_protect.schema.yml index cdd938e..0cc02b4 100644 --- a/config/schema/turnstile_protect.schema.yml +++ b/config/schema/turnstile_protect.schema.yml @@ -27,3 +27,6 @@ turnstile_protect.settings: max_challenges: type: integer label: 'The maximum times the client can be challenged in a session before sending 429 responses' + history_enabled: + type: boolean + label: 'Save a daily snapshot of the flood information on your site' diff --git a/src/Form/Settings.php b/src/Form/Settings.php index 91433c3..9a8c5bc 100644 --- a/src/Form/Settings.php +++ b/src/Form/Settings.php @@ -130,6 +130,13 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#min' => 1, ]; + $form['history_enabled'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Enable History'), + '#description' => $this->t('Enable or disable history tracking in Turnstile Protect.'), + '#default_value' => $config->get('history_enabled'), + ]; + return parent::buildForm($form, $form_state); } @@ -152,6 +159,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { ->set('threshold', (int) $form_state->getValue('threshold')) ->set('window', (int) $form_state->getValue('window')) ->set('max_challenges', (int) $form_state->getValue('max_challenges')) + ->set('history_enabled', (bool) $form_state->getValue('history_enabled')) ->save(); parent::submitForm($form, $form_state); diff --git a/turnstile_protect.install b/turnstile_protect.install new file mode 100644 index 0000000..4f81e08 --- /dev/null +++ b/turnstile_protect.install @@ -0,0 +1,55 @@ + 'Stores the history of requests by IP range.', + 'fields' => [ + 'timestamp' => [ + 'description' => 'The Unix timestamp of the record.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ], + 'ip_range' => [ + 'description' => 'The IP range being tracked.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ], + 'requests' => [ + 'description' => 'The number of requests by the IP range.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ], + ], + 'indexes' => [ + 'ip_range' => ['ip_range'], + ], + ]; + + return $schema; +} + +/** + * Adds the turnstile_protect_history table. + */ +function turnstile_protect_update_10001() { + $schema = Database::getConnection()->schema(); + if (!$schema->tableExists('turnstile_protect_history')) { + // Create the table using the schema definition from hook_schema(). + $schema_definition = turnstile_protect_schema(); + $schema->createTable('turnstile_protect_history', $schema_definition['turnstile_protect_history']); + } + +} diff --git a/turnstile_protect.module b/turnstile_protect.module index 5799f18..ab91c51 100644 --- a/turnstile_protect.module +++ b/turnstile_protect.module @@ -21,3 +21,30 @@ function turnstile_protect_captcha_alter(&$captcha, $info) { $captcha['form']['turnstile_widget']['#markup'] = str_replace('get('history_enabled')) { + return; + } + + $threshold_timestamp = \Drupal::time()->getRequestTime() - $config->get('window'); + // add some padding to prevent missing a whole day of metrics + $threshold_timestamp -= 300; + $result = \Drupal::database()->query("SELECT MAX(timestamp) FROM {turnstile_protect_history}")->fetchField(); + if ($result && $result > $threshold_timestamp) { + return; + } + + \Drupal::database()->query("INSERT INTO {turnstile_protect_history} (`timestamp`, ip_range, requests) + SELECT UNIX_TIMESTAMP(), identifier, COUNT(*) + FROM {flood} + WHERE `event` = :event + GROUP BY identifier + ORDER BY COUNT(*) DESC", [ + ':event' => 'turnstile_protect_rate_limit', + ]); +}