as I understand, it seems to be possible to use both v2 and v3 on the same page (see https://github.com/google/recaptcha/issues/279), but can't find any example of it :/
I already have HTML pages with invisible v2, and first, I want to evaluate the accuracy of the v3 score without breaking my current v2 (v3 will be only for test purposes). I was also wondering if it could be possible to use v3 and render v2 challenges for low scores.
Any idea ?
(sorry for my english, it's not my mother tongue ;)
Yes, this explains how : Can I run reCAPTCHA v2 and v3 on the same page?
Worked well with two v3 and one v2 checkbox on the same page.
The following example (written by Anton Cherniavskyi) works.
However, I think it only works with v2 invisible + v3, ie.: You can't use v2 checkbox + v3.
<script src="https://www.google.com/recaptcha/api.js?onload=v2_onload"></script>
<script src="https://www.google.com/recaptcha/api.js?onload=v3_onload&render=V3_SITE_KEY"></script>
<div class="g-recaptcha" data-size="invisible" data-sitekey="V2_INVISIBLE_SITE_KEY" data-callback="v2_callback"></div>
<script type="text/javascript">
function v2_onload() { console.log('v2 loaded'); }
function v3_onload() { console.log('v3 loaded'); }
function v2_callback(token) { console.log('v2 token: ' + token); }
function v3_callback(token) { console.log('v3 token: ' + token); }
// call these manually
function test_v2() { grecaptcha.execute(); }
function test_v3() { grecaptcha.execute(V3_SITE_KEY/*, {action: '...'}*/).then(v3_callback); }
</script>
Related
I have reCAPTCHA v3 set up on my page:
<script src="https://www.google.com/recaptcha/api.js?render=MY_KEY"></script>
If internet connectivity becomes unavailable or unreliable, reCAPTCHA will insert this HTML at the bottom of my page:
<div>
<div>
Could not connect to the reCAPTCHA service. Please check your internet connection and reload to get a reCAPTCHA challenge.
</div>
</div>
I would much rather handle this error in my JavaScript so I can display it to the user in a better way. However, the documentation for v3 doesn't indicate how to do this.
Any thoughts on how to catch this error?
You can put an onerror handler in the script tag itself:
<script src="https://www.google.com/recaptcha/api.js?render=MY_KEY" onerror="error_handler()">
But I think what you want is more along the lines of what reCAPTCHA v2 offers:
widgetId = grecaptcha.render('example1', {
'sitekey' : 'your_site_key',
'theme' : 'light',
'error-callback' : error_handler()
});
I doubt that works but there is another way. You just need to monitor the DOM for changes since you know that when there is an error Google will add a div to your page. You can do that with MutationObserver.
var m = new MutationObserver(function (mutationRecords) {
this.disconnect();
error_handler();
});
m.observe(document.body, {childList: true});
{childList: true} tells the MutationObserver to detect nodes added to the DOM and passes them to the callback function as the parameter mutationRecords (which contains array of MutationRecord objects). From there it's up to you what to do next.
This should at least be enough to get you started!
This is Yet another error 403 on Google Sheets API. Um trying to read the data from a Spreadsheet and expose it on a website, using some custom HTML filters.
So, there is this question:
Error 403 on Google Sheets API
Still, I cannot figure out what to do. I have setup my service account in the google cloud platform, granted it permissions to access my Spreadsheet - I have even made my SpreadSheet accessible via link (but that is restricted to emails from my organization, so it seems useless anyway). I've also activated domain-wide delegation for my service account - didn't make any difference at all. I'm pretty sure the issue is not related to a wrong key or some typo because, when I remove the access to the service email from the sheet, I steel get a 403 error, but it comes with a message saying the caller doesn't have access to that spreadsheet.
People keep mentioning OAuth, but I don't want to use that, since I'm intending to use a simple API access, as in this Google GitHub example. I'm using my business account, so there might be some issue related to that.
Here is the HTML (which I'm running from a simple HTTP server on python, not directly, given the fact the GAPI doesn't handle localhost/ sources very well):
<!DOCTYPE html>
<html>
<head>
<title>Google Sheets API Quickstart</title>
<meta charset="utf-8" />
</head>
<body>
<p>Google Sheets API Quickstart</p>
<!--Add buttons to initiate auth sequence and sign out-->
<button id="authorize_button" style="display: none;">Authorize</button>
<button id="signout_button" style="display: none;">Sign Out</button>
<pre id="content" style="white-space: pre-wrap;"></pre>
<script type="text/javascript">
// Client ID and API key from the Developer Console
var API_KEY = 'My-API-KEY';
var DISCOVERY_DOCS = ["https://sheets.googleapis.com/$discovery/rest?version=v4"];
var SCOPES = "https://www.googleapis.com/auth/spreadsheets.readonly";
function handleClientLoad() {
gapi.load('client', initClient);
}
function initClient() {
gapi.client.init({
apiKey: API_KEY,
discoveryDocs: DISCOVERY_DOCS
}).then(function(){listMajors();})
}
function appendPre(message) {
var pre = document.getElementById('content');
var textContent = document.createTextNode(message + '\n');
pre.appendChild(textContent);
}
function listMajors() {
gapi.client.sheets.spreadsheets.values.get({
spreadsheetId: 'my-spreadsheet-id',
range: 'Sheet1!A1:A10',
}).then(function(response) {
var range = response.result;
if (range.values.length > 0) {
appendPre('Name, Major:');
for (i = 0; i < range.values.length; i++) {
var row = range.values[i];
// Print columns A and E, which correspond to indices 0 and 4.
appendPre(row[0] + ', ' + row[4]);
}
} else {
appendPre('No data found.');
}
}, function(response) {
appendPre('Error: ' + response.result.error.message);
});
}
</script>
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === lete') this.onload()">
</script>
</body>
</html>
Does anyone have anyclue on what I'm missing, or what else can I try?
Edit: sharing the spreadsheet publicly is not an option. The is a business email, and, therefore, the only option I've got here is sharing it domain wide, as I've already stated above. Also, this is a business spreadsheet, and therefofe contains sentitive data. Doesn't really make sense to expose it publicly. Besides that, I've already shared the spreadsheet with the service email. What I'm trying to achieve, after all, is to read the data from the spreadsheet without using oauth, and emdding it on a website (I know there is a built-in embed tool, but that doesn't suit me because I need to add a html filter).
If you try to access a Spreadsheet that is not public, you will have to use OAuth 2.0. Since it is not a public resource, you have to use the credentials of an account that has access to this resource.
In the example you provided, they are accessing a public resource, so the API key is enough. That's not your case.
Reference:
Using OAuth 2.0 to Access Google APIs
I'm keen to use reCAPTCHA v3 for logins and stuff, but I'm unsure what to do with a 'low rating', it doesn't feel safe to deny access with no way for the user to move forward. What feels like a more complete solution would be to combine the "rating" from v3 with a puzzle challenge from v2 if the score is too low. How are other people approaching this issue?
Also, it appears that v3's grecaptcha.execute returns a similar result to v2, that is too say that it's not returning a rating, just a TOKEN which is verified in a similar way to v2?
I've code i found to demonstrate that they can both be used in the same HTML...
<!-- https://github.com/google/recaptcha/issues/279 -->
<script src="https://www.google.com/recaptcha/api.js?onload=v2_onload"></script>
<script src="https://www.google.com/recaptcha/api.js?onload=v3_onload&render=V3_SITE_KEY"></script>
<script src='https://www.google.com/recaptcha/api.js?render=V3_SITE_KEY'></script>
<div class="g-recaptcha" data-size="invisible" data-sitekey="V2_SITE_KEY" data-callback="v2_callback"></div>
<script type="text/javascript">
function v2_onload() { console.log('v2 loaded'); }
function v3_onload() { console.log('v3 loaded'); }
function v2_callback(token) { console.log('v2 token: ' + token); }
function v3_callback(token, score) { console.log('v3 token: ' + token + " ----- " + score); }
// call these manually
function test_v2() { grecaptcha.execute(); }
function test_v3() {
grecaptcha.execute('V3_SITE_KEY' , {action:'thisIsATest' }).then(v3_callback);
}
I have concerns then that if v3 requires sever-side validation, in order to implement v2 as well, either a page reload to invoke v2 (when server-side says "low rating" then reload and enable v2) OR v3 sever-side validation could be done via an ajax call, but that feels like something that can be inspected and manipulated by a bot (grab ajax response, change 'no' to 'yes' and then have the bot call the 'callback' function itself to gain access).
Any help or suggestions would be appreciated.
It looks like there is an answer to this question on the official Frequently Asked Questions website of reCAPTCHA.
Can I run reCAPTCHA v2 and v3 on the same page?
To do this, load the v3 site key as documented, and then explicitly render v2 using grecaptcha.render.
<html>
<head>
<title>reCAPTCHA demo: Running both v2 and v3</title>
<script src="https://www.google.com/recaptcha/api.js?render=v3_site_key"></script>
<script>
grecaptcha.ready(() => {
grecaptcha.render('html_element', {
'sitekey' : 'v2_site_key'
});
});
</script>
<script>
function onSubmit() {
grecaptcha.ready(() => {
grecaptcha.execute('v3_site_key', {action: 'homepage'}).then((token) => {
...
});
});
}
</script>
</head>
</html>
Wouldn't it be simplest to just send the token with your form post and double check it server side? I know you're still possibly allowing a bot to post data into your system, but a bot that can sneak by google should be pretty rare. And the first thing your sever side logic should do is verify the token, which can't easily be faked. That said in my initial analysis of google V3(10K requests) the bot detection was solidly binary, in that all the scores were above or below .5 . Google in their documentation recommends different strategies for how to deal with suspicious traffic based on the scenario.
https://developers.google.com/recaptcha/docs/v3.
This code in a simple HTML file works:
<script>
function load() {
alert("load event detected!");
}
window.onload = load;
</script>
However, if I put it into the index.html file of an AngularJS web app, it does not. Does anybody know why not?
Call your function with ng-init
var app = angular.module('app',[]);
app.controller('myController', function($scope){
$scope.load = function () {
alert("load event detected!");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app'>
<div ng-controller='myController' ng-init='load()'></div>
</div>
I prefer putting this kind of code in the app.run() function of angular.
e.g.
angular
.module('testApp', ['someModule'])
.constant('aConstant', 'hi')
.config(function($rootProvider) {/*some routing here*/})
.run(['$window', function($window) {
$window.onload = function() {/*do your thing*/};
}]);
also check this nice post that depicts the order that some things happen in angular
AngularJS app.run() documentation?
the following should work:
jQuery(function(){ /** my window onload functions **/ })
since angular uses a subset of jquery anyways you also may include the real thing.
better yet:
Instead of using this, you may consider using the angular way of initialising things:
that would be: http://docs.angularjs.org/api/ng.directive:ngInit
< any ng-init="functionInController(something)"...
to make it invisible until init: http://docs.angularjs.org/api/ng.directive:ngCloak
< any ng-cloak .....
to initialise/customize whole parts: http://docs.angularjs.org/guide/directive
< any directive-name....
Try
angular.element($window).bind('load', function() {
});
I understand the cross-domain error when using ajax to try to obtain information from another website but according to jQuery you should be able to use a jsonp request instead. I am stumped on how to achieve this when trying to display recaptcha. The issue is I am unable to use the plugin to achieve this, which would make it so much easier.
<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
<script type="text/javascript">
function showRecaptcha() {
Recaptcha.create("// removed for example", 'captchadiv', {
tabindex: 1,
theme: "red",
callback: Recaptcha.focus_response_field
});
}
jQuery(document).ready(function(){
showRecaptcha('recaptcha_div');
jQuery('#contact-form').submit(function(){
var challenge = Recaptcha.get_challenge();
var response = Recaptcha.get_response();
var ip = "<?php print $_SERVER['REMOTE_ADDR'] ?>";
var private = "// removed for example";
var requestUrl = "http://www.google.com/recaptcha/api/verify?privatekey=" + private + "&remoteip=" + ip + "&challenge=" + challenge + "&response=" + response;
jQuery.getJSON(requestUrl, function(json) {
alert("what");
});
})
});
</script>
<form id="">
// Form stuff
</form>
<div id="captchadiv"></div>
<input type="submit" name="submit" id="form-submit">
How should I call this to googles server and obtain the correct callback. It's basically going to return a true or false. I either get the infamous Access-Control-Allow-Login or or an error regarding plain/text. Anyone with suggestions?
1) Google does not support JSONP output. Why? Go to 2).
2) reCAPTCHA is meant to be validated on server side code. Why? Go to 3).
3) Spammers can easily bypass your client side validation code, thus rendering any CAPTCHA solution pointless.
You can try this way, Invisible reCAPTCHA
https://developers.google.com/recaptcha/docs/invisible