Skip to content

Commit

Permalink
feat(log): option to log spam or all submissions
Browse files Browse the repository at this point in the history
  • Loading branch information
vandres committed May 17, 2024
1 parent dfa05aa commit 5c8cb3d
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 3 deletions.
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,40 @@ You can use the settings dialog in the control panel. But I would recommend crea
```php
return [
'secondsSpentOnFormThreshold' => 3, // 0 to disable
'logSpam' => false,
'logAll' => false,
];

```

## Usage

Just add the following `prepareSubmission()` call somewhere in the form template. Example:

```twig
<form sprig s-method="post" s-action="contact-form/send" accept-charset="UTF-8">
{# prepare form submission check #}
{{ craft.form.service.prepareSubmission() }}
{{ hiddenInput('fromName', title ) }}
{% if page is defined and page %}
{{ redirectInput(page.url) }}
{% endif %}
</form>
```

If you forget that call, all submissions might be marked as spam!

### Edge Case

If you cache the contact form, the `prepareSubmission()` might not be called and the form would misbehave.

This is out of the scope of this plugin. I would recommend not caching contact forms or using some kind of AJAX solution. My preference is a combination of the plugins "No-Cache" and "Sprig".

## Roadmap

- simple spam protection via "time spent on form"
- write filtered submissions to log (configurable)
- ~~simple spam protection via "time spent on form"~~
- ~~write filtered submissions to log (configurable)~~

## Support my work

Expand Down
22 changes: 21 additions & 1 deletion src/ContactFormExtended.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
use craft\base\Plugin;
use craft\contactform\events\SendEvent;
use craft\contactform\Mailer;
use craft\log\MonologTarget;
use craft\web\twig\variables\CraftVariable;
use Psr\Log\LogLevel;
use vandres\craftcontactformextended\models\Settings;
use vandres\craftcontactformextended\services\FormService;
use vandres\craftcontactformextended\variables\FormVariable;
Expand Down Expand Up @@ -111,16 +113,34 @@ function (Event $event) {
return;
}

Craft::getLogger()->dispatcher->targets[] = new MonologTarget([
'name' => 'contact-form-extended',
'categories' => ['contact-form-extended'],
'level' => LogLevel::INFO,
'logContext' => true,
'allowLineBreaks' => true,
'maxFiles' => 30,
]);

Event::on(
Mailer::class,
Mailer::EVENT_BEFORE_SEND,
function (SendEvent $event) {
// is $event already marked as spam?
if ($event->isSpam) {
$this->formService->logSpam('Caught by Contact Form Honeypot', $event->submission, Craft::$app->getRequest());
}

try {
$this->formService->checkSubmission();
} catch (\Exception $error) {
// TODO write log
Craft::warning($error->getMessage());
$event->isSpam = true;
$this->formService->logSpam($error->getMessage(), $event->submission, Craft::$app->getRequest());
}

if (!$event->isSpam) {
$this->formService->logAll('Successful submission', $event->submission, Craft::$app->getRequest());
}
}
);
Expand Down
5 changes: 5 additions & 0 deletions src/models/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ class Settings extends Model
{
public int $secondsSpentOnFormThreshold = 0;

public bool $logSpam = false;

public bool $logAll = false;

public function defineRules(): array
{
return [
[['secondsSpentOnFormThreshold'], 'integer', 'min' => 0],
[['logSpam', 'logAll'], 'boolean'],
];
}
}
25 changes: 25 additions & 0 deletions src/services/FormService.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ public function prepareSubmission(): void
public function checkSubmission(): void
{
$settings = ContactFormExtended::getInstance()->getSettings();
if ($settings->secondsSpentOnFormThreshold <= 0) {
$this->reset();
return;
}

$start = Craft::$app->getSession()->get(self::SESSION_KEY . ContactFormExtended::getInstance()->schemaVersion);

if (!$start) {
Expand All @@ -35,6 +40,26 @@ public function checkSubmission(): void
$this->reset();
}

public function logSpam($message, $submission)
{
$settings = ContactFormExtended::getInstance()->getSettings();
if (!$settings->logSpam) {
return;
}

Craft::error($message . "\n" . print_r($submission->attributes, true), 'contact-form-extended');
}

public function logAll($message, $submission)
{
$settings = ContactFormExtended::getInstance()->getSettings();
if (!$settings->logAll) {
return;
}

Craft::info($message . "\n" . print_r($submission->attributes, true), 'contact-form-extended');
}

private function reset(): void
{
Craft::$app->getSession()->remove(self::SESSION_KEY . ContactFormExtended::getInstance()->schemaVersion);
Expand Down
20 changes: 20 additions & 0 deletions src/templates/_settings.twig
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,23 @@
disabled: 'secondsSpentOnFormThreshold' in overrides,
warning: 'secondsSpentOnFormThreshold' in overrides ? configWarning('secondsSpentOnFormThreshold'),
}) }}

{{ forms.lightswitchField({
label: "Log spam"|t('contact-form-extended'),
id: 'logSpam',
name: 'logSpam',
instructions: "Logs spam to a file „contact-form-extended-[Y-m-d]“"|t('contact-form-extended'),
on: settings.logSpam,
disabled: 'logSpam' in overrides,
warning: 'logSpam' in overrides ? configWarning('logSpam'),
}) }}

{{ forms.lightswitchField({
label: "Log all"|t('contact-form-extended'),
id: 'logAll',
name: 'logAll',
instructions: "Logs all submission to a file „contact-form-extended-[Y-m-d]“"|t('contact-form-extended'),
on: settings.logAll,
disabled: 'logAll' in overrides,
warning: 'logAll' in overrides ? configWarning('logAll'),
}) }}
4 changes: 4 additions & 0 deletions src/translations/de/contact-form-extended.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

return [
'Time spend on form (in seconds)' => 'Zeitaufwand für das Formular (in Sekunden)',
'Log spam' => 'Spam loggen',
'Logs spam to a file „contact-form-extended-[Y-m-d]“' => 'Spam wird in einer Datei „contact-form-extended-[Y-m-d]“ geloggt.',
'Log all' => 'Alles loggen',
'Logs all submission to a file „contact-form-extended-[Y-m-d]“' => 'Alle Mitteilungen werden in einer Datei „contact-form-extended-[Y-m-d]“ geloggt.',
'Set the time, how long a user needs to spend time on the form, to not be suspected a bot. Leave empty or set to „0“ to disable.' => 'Angabe der Sekunden, wie lange ein Benutzer auf dem Formular verweilen muss, um nicht als Bot verdächtigt zu werden. Leer lassen oder auf „0“ setzen, um zu deaktivieren.',
'This is being overridden by the {setting} config setting in your {file} config file.' => 'Dies wird durch die {setting} Einstellung in der {file} Config-Datei überschrieben.',
];
4 changes: 4 additions & 0 deletions src/translations/en/contact-form-extended.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

return [
'Time spend on form (in seconds)' => '',
'Log spam' => '',
'Logs spam to a file „contact-form-extended-[Y-m-d]“' => '',
'Log all' => '',
'Logs all submission to a file „contact-form-extended-[Y-m-d]“' => '',
'Set the time, how long a user needs to spend time on the form, to not be suspected a bot. Leave empty or set to „0“ to disable.' => '',
'This is being overridden by the {setting} config setting in your {file} config file.' => '',
];

0 comments on commit 5c8cb3d

Please sign in to comment.