reCaptcha V3 fails validation on first form submission only - javascript

I am trying to set up reCaptcha v3 and it sort of works. For some reason the first time I submit the form it fails but from the second submit onwards it is fine. I can't figure out why this is happening?
<script src="https://www.google.com/recaptcha/api.js?render=MY_SITE_KEY"></script>
<script>
grecaptcha.ready(function () {
grecaptcha.execute('MY_SITE_KEY', { action: 'contact' }).then(function (token) {
var recaptchaResponse = document.getElementById('captcha-response');
recaptchaResponse.value = token;
});
});
</script>
<input type="hidden" name="captcha-response" id="captcha-response">
PHP
$verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$secretKey.'&response='.$_POST['captcha-response']);
$responseData = json_decode($verifyResponse);
if(!$responseData->score < 0.5) {
$message .= "Verification failed " . $responseData->score;
}
When I submit the form the first time, I get the validation error but my score is 0.9.

Why you have added "!" with "$responseData->score"? you may need to replace your condition with the following:
Replace this:
if(!$responseData->score < 0.5) {
$message .= "Verification failed " . $responseData->score;
}
With this one:
if($responseData->score < 0.5) {
$message .= "Verification failed " . $responseData->score;
}
P.S: Following code takes few seconds to properly load and get a "captcha-reponse" code, so you may need to disable all submit button and wait till you got a "captcha-reponse" to enable the submit button in form or you needs to implementent another way to delay the submit to execute only once you got a "captcha-response" code otherwise you will keep getting "missing-input-response" error message
<script src="https://www.google.com/recaptcha/api.js?render=MY_SITE_KEY"></script>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('MY_SITE_KEY', {
action: 'contact'
}).then(function(token) {
var recaptchaResponse = document.getElementById('captcha-response');
recaptchaResponse.value = token;
});
});
</script>

You should re-generate the reCaptcha token after error form validation occured.
The token reCaptcha only valid for ONE TIME.
So, you have two options to fixes this issue.
1. Reload the page when error occured
This is the easiest way. You only need to reload the page whenever form validation error occured.
Of course, this will trigger the reCaptcha to generate new token.
2. Handle with AJAX (Non-reload page)
This is the best approach, since this will helps the user not losing the form data and continue to fill the form.
So, here's what you should do.
<!-- Put this hidden input inside of your form tag -->
<input name="_recaptcha" type="hidden">
<script src="https://www.google.com/recaptcha/api.js?render=YOUR_SITEKEY_HERE"></script>
<script>
// This will generate reCaptcha token and set to input hidden
const generateRecaptcha = function() {
grecaptcha.execute(
"YOUR_SITEKEY_HERE", {
action: "YOUR_ACTION_NAME"
}).then(function(token) {
if (token) {
document.querySelector("input[name='_recaptcha']").value = token;
}
});
}
// Call it when page successfully loaded
grecaptcha.ready(function() {
generateRecaptcha();
});
// Do your AJAX code here
$.ajax({
url: "https://example.com",
success: function(response) {
console.log(response);
},
error: function(error) {
// Call again the generator token reCaptcha whenever error occured
generateRecaptcha();
}
</script>
Don't forget to put your Site key and your action name. Make sure the action name matches with your Backend action name.
Medium Article

Related

form action redirect from JS (reCaptcha)

I have a submit form, after checking the captcha v3, I need to send the form with the same values. how to do this after receiving the token from the captcha?
With the code below, either a human or a bot outputs to the browser console, but does not redirect to the desired page
.then(result => {
if (result['om_score'] >= 0.5) {
console.log('Human')
} else {
console.log('Bot')
}
});
If i use window.location = "mail.php"; insted of console.log it send empty request
My goal is that the redirect would be to the <from> action with the entered values.
You can use JS to submit the form. Suppose you have the following form:
<form id="myform" action="mail.php" method="post">
....
</form>
You can use JS to submit it:
....
.then(result => {
if (result['om_score'] >= 0.5) {
console.log('Human')
document.getElementById("myform").submit();
} else {
console.log('Bot')
}
});
As a side note, you shouldn't be checking the Captcha client-side because it can easily be spoofed.

Updating a calculated field in the parent record after submitting/updating child record in a modal dialogue

I have a bit of an issue updating a calculated field of the parent form when submitting/updating a child record with a bootstrap 3 modal dialogue, from within the parent form.
I have this function in parent.js file:
function update_lineitems_subtotal() {
var qid = $j('[name=SelectedID]').val();
if (!isNaN(qid)) {
$j.ajax({
url: 'hooks/ajax_quote_subtotal.php',
data: {qid: qid},
success: function(data) {
$j('#LineItemsSubtotal').val(data);
$j('#Shipping').keyup();
}
});
} else {
$j('#LineItemsSubtotal').val('0');
$j('#Shipping').keyup();
}
};
And this is the ajax_quote_subtotal.php that runs with the ajax call above:
<?php
$currDir = dirname(__FILE__) . '/..';
include("$currDir/defaultLang.php");
include("$currDir/language.php");
include("$currDir/lib.php");
/* grant access to users with access to quotations table */
$od_from = get_sql_from('quotations');
if(!$od_from){
header('HTTP/1.0 401 Unauthorized');
echo "You do not have permission to access this page. If this behaviour is unexpected, please contact the system administrator";
exit;
}
$qid = intval($_REQUEST['qid']);
if(!qid) exit;
$parts_subtotal = sqlValue("select sum(Subtotal) from product_line_items where QuotationID='{$qid}' ");
$service_subtotal = sqlValue("select sum(Subtotal) from service_line_items where QuotationID='{$qid}' ");
$subtotal = $parts_subtotal + $service_subtotal;
sql("update quotations set LineItemsSubtotal='{$subtotal}' where QuotationID='{$qid}' ", $eo);
echo number_format($subtotal, 2);
?>
This is the function from child.js that closes the modal dialogue when the form is submitted and runs the update_lineitems_subtotal function from the parent.js
if($j('input[name=Embedded]').val()==1){
$j('form').submit(function(){
window.parent.jQuery('.modal').modal('hide');
setTimeout(function(){
parent.update_lineitems_subtotal();
}, 100);
})
}
This works as long as I do not remove setTimeout,however I do not feel like it is a good solution.
If the setTiemout is removed the record is created but it looks like the function runs before the child record is submitted, so the value of the subtotal field in the parent excludes the latest added record.
I have also tried this:
if($j('input[name=Embedded]').val()==1){
$j('form').submit(function(e){
e.preventDefault();
this.submit();
window.parent.jQuery('.modal').modal('hide');
parent.update_lineitems_subtotal();
})
}
This had similar results in Chrome and refused to even create a child record in Firefox.
Any help would be appreciated.
P.S. I am new to this, if you have time to explain the code you may suggest it would be greatly appreciated.

Customize Stripe error messages with JavaScript

I am using Stripe and "custom forms" from the API. The following code is throwing errors if something is wrong, in English, but I want to translate some of the error messages into Norwegian to make it more user friendly for my customers. For example "invalid_expiry_year" and "invalid_expiry_month" which is currently in English.
Is it possible to achieve and if so, how?
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript">
Stripe.setPublishableKey('pk_test_2iA9ERjj5lVuUgvOS9W5fNtV');
$(function() {
var $form = $('#payment-form');
$form.submit(function(event) {
// Disable the submit button to prevent repeated clicks:
$form.find('.submit').prop('disabled', true);
// Request a token from Stripe:
Stripe.card.createToken($form, stripeResponseHandler);
// Prevent the form from being submitted:
return false;
});
});
function stripeResponseHandler(status, response) {
function stripeHandler( status, response ){
if ( response.error && response.error.type == 'card_error' ){
$( '.errors' ).text( errorMessages[ response.error.code ] );
}
else {
// do other stuff (and handle api/request errors)
}
}
// Grab the form:
var $form = $('#payment-form');
if (response.error) { // Problem
// Show the errors on the form:
$form.find('.payment-errors').text(response.error.message);
$form.find('.submit').prop('disabled', false); // Re-enable submission
} else { // Token was created!
// Get the token ID:
var token = response.id;
// Insert the token ID into the form so it gets submitted to the server:
$form.append($('<input type="hidden" name="stripeToken">').val(token));
// Submit the form:
$form.get(0).submit();
}
};
</script>
There is an option for you to set up the stripe form in a different language than English, but only for a few other languages Stripe supports. For a custom integration, you will have to pass locale: 'auto' when calling StripeCheckout.configure() so the language will be detected automatically. There’s more info in the docs.
However, since Norwegian isn't supported yet, what I am suggesting is mapping the response codes and providing your own translations for the errors.
var errorMessages = {
incorrect_number: "The card number is incorrect.",
....
};
You can find a complete list with all error codes here

Promise to execute a particular code first

I have the following scenario. Actual Page loading starts, user login is checked for authentication. If access granted, actual page loading completes and user can access the page. If access denied, actual page loading stops and user is redirected to 'access denied' page.
Infact the scenario should be like this. User authentication is checked. if access granted, actual page loading starts and user can access page. If access denied, user is directly directed to 'access denied' page.
can someone tell me how to include promise for this scenario. current code is as follows.
$q.when().then(function () {
return $rootScope.$emit('resetView', false, 'default');
}).then(function (result) {
loadNavBar(); //actual page loading starts here
}, function (error) {
$log.error("Caught an error:", error);
return $q.reject('New error');
});
the below function is loadNavBar() which gets executed. User authentication is done inside of this. Hence page loading starts and then user is checked. I want user to be checked first itself and then load page accordingly depending on his access rights.
var loadNavBar = function () {
//few functions here to display page.
//below code to check user authentication
var serviceURL_CheckUserExists = '/api/Pre/CheckUserExists';
//ajax to check if user exists in database. give/ deny access based on user present in DB and if user is set as blockuser in db.
$.ajax({
type: "GET",
url: serviceURL_CheckUserExists,
}).then(function (response) {
if (response.Results.length == 1 && response.Results[0].BlockUser == false) { //user has access if condition is satisfied.
$rootScope.myLayout.eventHub.emit('getUserName', response.Results[0].User_ID.trim());
$scope.role = "";
var details = response.Results[0];
for (var parameters in details) {
if (details[parameters] == true) {
$scope.role += parameters + ',';
}
}
$scope.role = $scope.role.replace(/.$/, ".");
var firstname = response.Results[0].FirstName;
firstname = firstname.replace(/\s/g, '');
$scope.$apply(function () {
$scope.username = response.Results[0].FirstName + " " + response.Results[0].LastName;
});
}
else { $window.location.href = '../../../BlockUser.html'; } //block access to actual page and redirect to 'access denied' page.
}
}
});
};
i think that the right approach to your problem is to use resolve property in the route, so the user can't navigate to certain pages if he isn't logged in and once he logged in you can inject the user object to the controller
for example to navigate to home page you must be logged in
.when("/home", {
templateUrl: "homeView.html",
controller: "homeController",
resolve: {
user: function(AuthenticationService){
return AuthenticationService.getUser();
}
}
})
app.controller("homeController", function ($scope, user) {
$scope.user = user;
});
https://www.sitepoint.com/implementing-authentication-angular-applications/
Here's a quick example of hiding the content until the user is authenticated to see it. Click the 'authenticate' button to trigger the function that you would run if the user is authenticated by your ajax call. Showing the content can be done with a fuction like:
function userIsAuthenticated(){
document.getElementById('pageContent').style.display = 'block';
}
See JsFiddle for a simple implementation.

Trying to pass <%> HTML Variable to Javascript - Node, Passport, and Stripe

A bit of a newbie here. I've been looking for an answer that works and found some similarities in a Jade problem but I'm not using Jade. I have passed an "user" attribute into an HTML view as so:
app.get('/profile', isLoggedIn, function(req, res) {
res.render('profilePage/profilePage.html', {
user : req.user // get the user out of session and pass to template
});
});
Then, in my profile HTML, I can access my user property like so:
<%=user.local.firstname%>'s Profile
However, I want to allow Stripe to send the user's credit card info via the Stripetoken. I have managed to include a variable amount from a text field the user inputs. However, I want to append the user property so I can use it in my callback. Here is the javascript/jquery that's included in the profile html:
<!-- New section -->
<script type="text/javascript">
<!-- Fill in your publishable key -->
Stripe.setPublishableKey('pkkey');
var stripeResponseHandler = function(status, response) {
var $form = $('#contactForm');
var $amount = $('#amount').val();
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
$form.find('button').prop('disabled', false);
} else {
// token contains id, last4, and card type
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
$form.append($('<input type="hidden" name="amount" />').val($amount));
// and re-submit
$form.get(0).submit();
}
};
jQuery(function($) {
$('#contactForm').submit(function(e) {
var $form = $(this);
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
Stripe.card.createToken($form, stripeResponseHandler);
// Prevent the form from submitting with the default action
return false;
});
});
</script>
As you can see, I have managed to append the $amount variable so I can access it in the callback:
module.exports = function(app, passport) {
app.post('/stripe', function(req,res) {
// =====STRIPETOKEN======
var transaction = req.body;
var stripeToken = transaction.stripeToken;
var donationAmount = transaction.amount;
stripe.customers.create({
source : stripeToken,
account_balance : 0
},function(err, customer) {
if (err) {
console.log(err);
} else {
console.log("Success!");
}});
// ====CREATE CHARGE======
var charge =
{
amount : donationAmount,
currency : 'USD',
card : stripeToken
};
stripe.charges.create(charge, function(err, charge) {
if(err)
console.log(err);
else
{
res.json(charge);
console.log('Successful charge sent to Stripe!');
console.log(charge);
};
});
// ====PROFILE PAGE REDIRECT=====
res.render('profilePage/profilePage.html', {
});
});
So here's my problem. I want to pass the user's information, kind of like I did the amount, into the post method so when it redirects on success, I can pass it back in the res.render function, as well as send it to Stripe for description purposes. The only thing I can think of is to put the user info in a hidden field in HTML and access it like that, but that sounds messy and not proper.
This is my first time posting here so I apologize if it was too lengthy or not specific enough. Thanks!
The answer was in the way I was declaring passport and stripe in my application. Make sure you declare passport after everything to make the user variable available to stripe and all views.

Categories

Resources