Skip to content

Commit

Permalink
Add turnstile validation rule
Browse files Browse the repository at this point in the history
  • Loading branch information
njoguamos committed Feb 11, 2024
1 parent 679a2c0 commit 6349624
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,4 @@ jobs:
run: composer show -D

- name: Execute tests
run: vendor/bin/pest --verbose
run: vendor/bin/pest
23 changes: 20 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,26 @@ Ensure your client side technology submit a turnstile token using a name defined

Upon submitting the form, the turnstile token will be validated against turnstile api. If it fails, the request will be redirected back with `status` message. You can handle this message however you want in client side.

### 2. As a validation rule
```text
@TODO: Working on it
### 2. As a validation rule (v2.x.x)

You can user the inbuilt validation to validate form input

```php
use NjoguAmos\Turnstile\Rules\TurnstileRule;

class RegisterRequest extends FormRequest
{
/** @return array<string, array> */
public function rules(): array
{
return [
# Other fields
'token' => ['required', new TurnstileRule() ],
];
}

# Other code
}
```

### 3. Manual
Expand Down
2 changes: 1 addition & 1 deletion resources/lang/en/turnstile.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

return [
'failed' => 'Turnstile verification failed. Refresh the page and try again.',
'failed' => "We couldn't verify if you're human. Please refresh the page and try again.",
'no_secret_key' => 'Secret key was not found. Please add the key to your services file.',
];
19 changes: 19 additions & 0 deletions src/Rules/TurnstileRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace NjoguAmos\Turnstile\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use NjoguAmos\Turnstile\Turnstile;

class TurnstileRule implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (! (new Turnstile())->validate(token: $value)) {
$fail(trans(key: 'turnstile::turnstile.failed'));
}
}
}
1 change: 1 addition & 0 deletions src/TurnstileServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public function configurePackage(Package $package): void
->name(name: 'turnstile')
->hasTranslations()
->hasConfigFile(configFileName: 'turnstile')
->hasTranslations()
->hasInstallCommand(callable: function (InstallCommand $command) {
$command
->startWith(callable: function (InstallCommand $command) {
Expand Down
21 changes: 21 additions & 0 deletions tests/Pest.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use Illuminate\Contracts\Validation\ValidationRule;
use NjoguAmos\Turnstile\Tests\TestCase;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
use Illuminate\Http\Request;
Expand All @@ -23,3 +24,23 @@ function setSecretKey(string $type): void

config()->set(key: 'turnstile.secretkey', value: $key);
}


expect()
->extend(name: 'toPassWith', extend: function (mixed $value) {
$rule = $this->value;

if (!$rule instanceof ValidationRule) {
throw new Exception(message: 'Value is not an invokable rule');
}

$passed = true;

$fail = function () use (&$passed) {
$passed = false;
};

$rule->validate(attribute: 'attribute', value: $value, fail: $fail);

expect(value: $passed)->toBeTrue();
});
30 changes: 30 additions & 0 deletions tests/Rules/TurnstileRuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

use NjoguAmos\Turnstile\Rules\TurnstileRule;

beforeEach(closure: function () {
$this->rule = new TurnstileRule();
});

it(description: 'passes with a valid token', closure: function () {
// Set a key that always passes
setSecretKey(type: 'valid');

expect(value:$this->rule)->toPassWith('DUMMY.TOKEN');
});

it(description: 'fails with an valid token', closure: function () {
// Set a key that always passes
setSecretKey(type: 'invalid');

expect(value:$this->rule)->not->toPassWith('DUMMY.TOKEN');
});

it(description: 'fails with a spent valid token', closure: function () {
// Set a key that always passes
setSecretKey(type: 'spent');

expect(value:$this->rule)->not->toPassWith('DUMMY.TOKEN');
});

0 comments on commit 6349624

Please sign in to comment.