Skip to content

Commit

Permalink
resolve reCaptcha on submit to prevent timeout
Browse files Browse the repository at this point in the history
Documentation warns against resolving reCaptcha on page load:
https://developers.google.com/recaptcha/docs/v3
> Note: reCAPTCHA tokens expire after two minutes. If you're protecting an action with reCAPTCHA, make sure to call execute when the user takes the action rather than on page load.

My modification does just that.
  • Loading branch information
xpavp03 authored and f3l1x committed Jan 4, 2021
1 parent e2f1366 commit 29edb10
Showing 1 changed file with 62 additions and 14 deletions.
76 changes: 62 additions & 14 deletions assets/invisibleRecaptcha.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,74 @@
(function(document, Nette, grecaptcha) {
var init = false;

// polyfill for closest() - method for traversing DOM and finding the closest parent matching given selector (form, in our case)
// @see https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
if (!Element.prototype.matches) {
Element.prototype.matches =
Element.prototype.msMatchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.webkitMatchesSelector;
}

if (!Element.prototype.closest) {
Element.prototype.closest = function(s) {
var el = this;

do {
if (Element.prototype.matches.call(el, s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}

Nette.recaptcha = function (grecaptcha) {
var items = document.getElementsByClassName('g-recaptcha');
var length = items.length;

if (length > 0) {
grecaptcha.ready(function () {
for (var i = 0; i < length; i++) {
grecaptcha.render(items[i]);
};
grecaptcha.execute().then(function (token) {
var inputs = document.getElementsByClassName('g-recaptcha-response');
for (var i = 0; i < items.length; i++) {
inputs[i].value = token;
};
});
});
init = true;
if (length === 0) {
return;
}

grecaptcha.ready(function () {
var resolved = false;
var submitListenerFactory = function(form) {
return function (e) {
// we already have reCaptcha response, or the form is invalid - or submission is prevented for some other, unknown reason
if (resolved || e.defaultPrevented) {
return;
}

e.preventDefault();

grecaptcha.execute().then(function (token) {
resolved = true;

// reCaptcha token expires after 2 minutes; make it 5 seconds earlier just in case network is slow
setTimeout(function(){ resolved = false; }, (2 * 60 - 5) * 1000);

var inputs = document.getElementsByClassName('g-recaptcha-response');
for (var i = 0; i < inputs.length; i++) {
inputs[i].value = token;
}

form.submit();
});
};
};

var form;
for (var i = 0; i < length; i++) {
grecaptcha.render(items[i]);

form = items[i].closest('form');
form.addEventListener('submit', submitListenerFactory(form));
}
});
init = true;
};

if (!init) {
Nette.recaptcha(grecaptcha);
}
})(document, Nette, grecaptcha);
})(document, Nette, grecaptcha);

0 comments on commit 29edb10

Please sign in to comment.