eXpl0it3r / kirby-uniform-recaptcha

Kirby 3 Plugin Extension for the Uniform Plugin
MIT License
3 stars 2 forks source link

Support for reCAPTCHA v3 #1

Open eXpl0it3r opened 3 years ago

eXpl0it3r commented 3 years ago

As this has been requested multiple times [1][2], I decided to take a look into adding support for reCAPTCHA v3.

To my surprise, it is fairly simple to implement, the guard code doesn't even need adjustments. But the front-end code ("reCAPTCHA field"), needs some adjustments and I'd like to hear people's opinion on this.

Current Situation

The field essentially just inserts the following HTML snippet: <div class="g-recaptcha" data-sitekey="<sitekey>"></div>

Solutions for reCAPTCHA v3

The documentation shows two ways to implement reCAPTCHA v3, but the second option would require a separate backend call for every random action, so it seems not very well suited.

For the first option, you'd automatically bind the challenge to a button. Meaning you'd add parameters to a <button> tag and a custom click handler that submits the form. My immediate idea would be to just add some parameters to the "existing" functions:

<?php echo recaptchaButton('Button Text', 'custom-btn-class') ?>

<button class="custom-btn-class g-recaptcha"  data-sitekey="reCAPTCHA_site_key" data-callback='onSubmit' data-action='submit'>Button Text</button>
<?= recaptchaScript('form-id') ?>

<script src="https://www.google.com/recaptcha/api.js"></script>
<script>
   function onSubmit(token) {
     document.getElementById("form-id").submit();
   }
</script>

My main issues with this approach are:

One solution that could be looked into is, to provide pre-defined snippets, which could be overwritten by the user, if they have different needs.

What are you thoughts on this approach?

mzur commented 3 years ago

I'm not sure about the "separate backend call for every random action" of the second option. Why not only onsubmit of the form? It seems more flexible to me. Also, the onSubmit of the button does not work if the form is submitted by pressing Enter, I think. What about this:

<?= recaptchaField() ?>

<input id="recaptcha_token" type="hidden" name="recaptcha_token">

<script>
  let input = document.getElementById('recaptcha_token');
  let callback = function (e) {
    e.preventDefault();
    grecaptcha.ready(function() {
      grecaptcha.execute('reCAPTCHA_site_key', {action: 'submit'}).then(function(token) {
        input.value = token;
        input.form.removeEventListener('submit', callback);
        input.form.submit();
      });
    });
  };
  input.form.bindEventListener('submit', callback);
</script>