Skip to content
This repository has been archived by the owner on Feb 17, 2022. It is now read-only.

Commit

Permalink
Merge pull request #24 from DarkGhostHunter/master
Browse files Browse the repository at this point in the history
Reworked frontend default script
  • Loading branch information
DarkGhostHunter authored May 27, 2020
2 parents f234c8e + 7dc977c commit 8157652
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 30 deletions.
4 changes: 4 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Help me support this package

ko_fi: DarkGhostHunter
custom: ['https://paypal.me/darkghosthunter']
36 changes: 30 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[![Latest Version on Packagist](https://img.shields.io/packagist/v/darkghosthunter/captchavel.svg?style=flat-square)](https://packagist.org/packages/darkghosthunter/captchavel) [![License](https://poser.pugx.org/darkghosthunter/captchavel/license)](https://packagist.org/packages/darkghosthunter/larapoke)
![](https://img.shields.io/packagist/php-v/darkghosthunter/captchavel.svg)
![](https://github.com/DarkGhostHunter/Captchavel/workflows/PHP%20Composer/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/DarkGhostHunter/Captchavel/badge.svg?branch=master)](https://coveralls.io/github/DarkGhostHunter/Captchavel?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/9571f57106069b5f3aac/maintainability)](https://codeclimate.com/github/DarkGhostHunter/Captchavel/maintainability)

# Captchavel

Easily integrate Google reCAPTCHA v3 into your Laravel application.
Expand Down Expand Up @@ -45,9 +46,32 @@ Just add the `data-recaptcha="true"` attribute to the forms where you want to ha
</form>
```

The Google reCAPTCHA script from Google will be automatically injected on all responses for better analytics.
The Google reCAPTCHA script from Google will be automatically injected on all responses for better analytics.

> Alternatively, you may want to use the [`manual` mode](#manual) if you want control on how to deal with the frontend reCAPTCHA script, or use a [personalized one](#editing-the-script-view).
#### Form submission prevented

Form submission is disabled by default until the token from reCAPTCHA is retrieved. If you want to disable this behaviour, append `data-recaptcha-dont-prevent` to the form:

> Alternatively, you may want to use the [`manual` mode](#manual) if you want control on how to deal with the frontend reCAPTCHA script.
```blade
<!-- This form will be submittable even if the token hasn't been retrieved yet -->
<form action="/login" method="post" data-recaptcha="true" data-recaptcha-dont-prevent="true">
<!-- ... -->
</form>
```

#### Token resolved helper

When the reCAPTCHA token is being retrieved for the form, the form will have the property `recaptcha_unresolved` set to `true`. You can use this property for your other scripts to conditionally allow submission or whatever.

```javascript
if (form.recaptcha_unresolved) {
alert('Wait until reCAPTCHA sends the token!');
} else {
form.submit();
}
```

### Backend

Expand Down Expand Up @@ -412,19 +436,19 @@ We're leaving the Contextual Binding to you, since your *requester* may need som

You can edit the script Blade view under by just creating a Blade template in `resources/vendor/captchavel/script.blade.php`.

This blade views requires the Google reCAPTCHA v3 script, and detects the forms that need a reCAPTCHA check to be injected inside the request to the application. The view receives the `$key` variable witch is just the reCAPTCHA v3 Site Key.
This blade view contains the reCAPTCHA script of the package. The view receives the `$key` variable witch is just the reCAPTCHA v3 Site Key.

There you can edit how the script is downloaded from Google, and how it checks for forms to link with the backend.
There you can edit how the script is downloaded from Google, and how it checks for forms to link with the backend, if the default script isn't enough for you.

### AJAX Requests

Depending of your application, AJAX Requests won't include the reCAPTCHA token. This may be for various reasons:
Depending on the application, AJAX Requests won't include the reCAPTCHA token. This may be for various reasons:

* Using virtual DOM frameworks like Vue and React.
* Creating a form after the page loaded with JavaScript.
* An AJAX Requests being done entirely in JavaScript.

In any of these scenarios, you may want disable the injection script and [use the reCAPATCHA v3 scripts directly](https://developers.google.com/recaptcha/docs/v3).
In any of these scenarios, you may want disable the injection script and [use the reCAPATCHA v3 scripts directly](https://developers.google.com/recaptcha/docs/v3) or your [custom script](#editing-the-script-view).

## License

Expand Down
72 changes: 48 additions & 24 deletions resources/views/script.blade.php
Original file line number Diff line number Diff line change
@@ -1,36 +1,60 @@
<script src="https://www.google.com/recaptcha/api.js?render={{ $key }}&onload=captchavelCallback" defer></script>
<script>
// Start Captchavel Script
window.captchavelCallback = function () {
let site_key = "{{ $key }}";
const recaptchaSiteKey = "{{ $key }}";
if (site_key === '') {
const recatpchaForms = Array.from(document.getElementsByTagName('form'))
.filter(form => form.dataset.recaptcha === 'true');
recatpchaForms.forEach((form) => {
if (! form.dataset.recaptchaDontPrevent) {
form.addEventListener('submit', event => {
if (form.recaptcha_unresolved) {
event.preventDefault();
}
});
}
})
window.captchavelCallback = () => {
if (recaptchaSiteKey === '') {
console.error("You haven't set your Site Key for reCAPTCHA v3. Get it on https://g.co/recaptcha/admin.");
return;
}
Array.from(document.getElementsByTagName('form'))
.filter((form) => form.dataset.recaptcha === 'true')
.forEach((form) => {
let action = form.action.includes('://') ? (new URL(form.action)).pathname : form.action;
form.addEventListener('submit', (event) => {
event.preventDefault();
grecaptcha.execute(site_key, {
action: action
.substring(action.indexOf('?'), action.length)
.replace(/[^A-z\/_]/gi, '')
}).then((token) => {
if (token) {
let child = document.createElement('input');
child.setAttribute('type', 'hidden');
child.setAttribute('name', '_recaptcha');
child.setAttribute('value', token);
form.appendChild(child);
form.submit();
}
});
});
function refreshToken(form) {
form.recaptcha_unresolved = true;
let action = form.action.includes('://') ? (new URL(form.action)).pathname : form.action;
console.log('action: ' + action)
grecaptcha.execute(recaptchaSiteKey, {
action: action.substring(action.indexOf('?'), action.length).replace(/[^A-z\/_]/gi, '')
}).then(token => {
// Remove all inputs with an old reCAPTCHA token.
form.removeChild(
Array.from(form.getElementsByTagName('input'))
.filter(input => input.name === '_recaptcha')
);
let child = document.createElement('input');
child.setAttribute('type', 'hidden');
child.setAttribute('name', '_recaptcha');
child.setAttribute('value', token);
form.appendChild(child);
form.recaptcha_unresolved = false;
});
}
recatpchaForms.forEach(form => {
refreshToken(form);
setInterval(() => refreshToken(form), 100 * 1000);
});
// If the user hits history back or forward, we will forcefully refresh the token.
window.addEventListener('popstate', () => {
recatpchaForms.forEach(form => {
refreshToken(form);
})
})
};
// End Captchavel Script
</script>

0 comments on commit 8157652

Please sign in to comment.