Open heliusAurelius opened 3 years ago
Doesn't really matter if you disable or even completely hide the submit button (from human eyes), bots just care about the gform link inside the HTML. Using JavaScript for validation is meaningless, as bots bypass these steps anyways - I've seen bots spamming with honeypot field filled (Fun fact: It even adds a new honeypot column to the contact form sheet).
As far as I can tell, validation absolutely needs to happen inside the Google Apps Script (.gs), and CORS is simply not letting it. Anything besides making that happen looks like a dead end to me.
Has anyone been successful implementing this validation in Google scripts yet? I found this tutorial, but haven’t been successful with my project yet http://www.googleappsscript.org/recent-additions/recaptchawithgoogleappsscript
In the link you have provided, it would work because everything happens (including the user interaction) in the Google Script thus inside the parent domain (which is x.google.com), but again due to CORS restrictions, this won't work when your website on your own domain (which can't be x.google.com) requests it.
the tutorial that @heliusAurelius posted does seem to allow custom domains (does that still not work with CORS though? it is possible that could still be a blocker)
I'd be curious if it could work, but I have not tried to see what happens in this case. it would be neat to have recaptcha built in, and it would make a nice enhancement for an advanced section of our tutorial here!
@mckennapsean Okay, so after you have said that it seems to allow custom domains, I have examined it again. It honestly looked like you were right, so I decided to give it another go. This time, voilà, it worked. My previous attempt may have been troubled by a completely different error, of which I may have falsely presumed as CORS related - I honestly don't know at this point.
Anyways, here's how I did it.
In form-submission-handler.js
, I passed the g-recaptcha-response
as a seperate form-specific value.
data.gRecaptchaResponse = document.getElementById("g-recaptcha-response").value;
In .gs
, I assigned a variable to it in the very first line of doPost
.
var r = String(e.parameters.gRecaptchaResponse);
Verified it with the function below just like in the tutorial @heliusAurelius posted.
function verifyCaptcha(r){
var pl = {
'secret' : secret,
'response': r
}
var url = 'https://www.google.com/recaptcha/api/siteverify';
var resp = UrlFetchApp.fetch(url, {
payload : pl,
method : 'POST'
}).getContentText();
return JSON.parse(resp).success;
}
Then bounded our main function to the verification.
if (verifyCaptcha(r)){
try {
...
} else return;
}
Also, we can add the following into form-submission-handler.js
to catch errors and give visitors some feedback.
xhr.onerror = function() {
//error stuff
}
This works in a variety of conditions, like an expired captcha or a JavaScript blocker on the visitors browser.
Any submission attempts without the solved recaptcha will also return this, but it is preferable that we enable the submit button after user solves the recaptcha anyways.
We can disable the button in the function loaded()
of form-submission-handler.js
, enable it with data-callback
when captcha is solved, and disable it again with data-expired-callback
when it expires.
Only bots will be able to attempt submitting a response without solving the recaptcha, but we finally don't need to care about them.
I will now push it to my master and try it out for a few days - will try to give an update with my results.
Update: Not a single spam for 5 days straight (it was around 2-5 spams/day). I have tried submitting forms to myself from different devices (Android, iOS, Windows 10, Windows 7) with different browsers (Firefox, Chrome, Opera) - no issues so far.
@bledatunay I was able to follow along with your guide up until the "bounded our main function to the verification" section. Where in the gscript do I add this code?
You will be putting your whole doPost
into an if
statement which verifies the captcha. It will look like this:
function doPost(e) {
var r = String(e.parameters.gresp);
if (verifyCaptcha(r)){
try {
Logger.log(e);
record_data(e);
var mailData = e.parameters;
var orderParameter = e.parameters.formDataNameOrder;
var dataOrder;
if (orderParameter) {
dataOrder = JSON.parse(orderParameter);
}
var sendEmailTo = (typeof TO_ADDRESS !== "undefined") ? TO_ADDRESS : mailData.formGoogleSendEmail;
if (sendEmailTo) {
MailApp.sendEmail({
to: String(sendEmailTo),
subject: "Contact form submitted",
htmlBody: formatMailBody(mailData, dataOrder)
});
}
return ContentService
.createTextOutput(
JSON.stringify({"result":"success",
"data": JSON.stringify(e.parameters) }))
.setMimeType(ContentService.MimeType.JSON);
} catch(error) {
Logger.log(error);
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": error}))
.setMimeType(ContentService.MimeType.JSON);
}} else return;
}
@bledatunay worked like a charm! Thank you!
I'll be testing over the next few days to ensure this recaptcha is working to prevent spam submissions as well
I managed to implement a simple Google reCAPTCHA validation in the form by adding in the reCAPTCHA, and using javascript to enable the submit button once it is solved. Doing so, captures the reCAPTCHA response in the sheet and email notification. But it seems that there are some bots which account for this and 're-enable' disabled submit buttons as well as ignoring my honeypot in the form.
Is there a way to add the required attribute to this reCAPTCHA response to prevent users/bots from simply re-enabling the submit button by editing the page code? When I add 'required' to the reCAPTCHA div, it doesn't validate the same way as the rest of the fields, and adding a script to return onsubmit="false" for the form seems to fire after the action="[google script]".
My form code is as follows:
I use page-level JS to re-enable the submit button once the reCAPTCHA is solved