VividCortex / angular-recaptcha

AngularJS directive to add a reCaptcha widget to your form
http://vividcortex.github.io/angular-recaptcha/
MIT License
496 stars 257 forks source link

Enable Invisible Recaptcha #174

Closed mattmeye closed 7 years ago

mattmeye commented 7 years ago

Invisible reCAPTCHA Integration

  1. If you haven’t integrated your site with reCAPTCHA v2 , please follow our developer guide for implementation details.
  2. Please make sure that your site key that has been whitelisted for Invisible reCAPTCHA.
  3. To enable the Invisible reCAPTCHA, rather than put the parameters in a div, you can add them directly to an html button. a. data-callback=””. This works just like the checkbox captcha, but is required for invisible. b. data-badge: This allows you to reposition the reCAPTCHA badge (i.e. logo and ‘protected by reCAPTCHA’ text) . Valid options as ‘bottomright’ (the default), ‘bottomleft’ or ‘inline’ which will put the badge directly above the button. If you make the badge inline, you can control the CSS of the badge directly.
  4. Verifying the user’s response has no changes.
TheSharpieOne commented 7 years ago

Invisible reCAPTCHA doesn't appear to be open to the general public yet (site currently says "Coming soon"). You have to go through a special registration process. This makes it difficult to integrate with and test. ref: https://www.google.com/recaptcha/intro/comingsoon/invisible.html

It would be interesting to see how this would integrate with the current code. Some concerns such as validation (ensuring the checkbox is checked) go away. Another things revolve around whether the directive will create the button or just be attached to one. Many of the other parameters are no longer available since they do not do anything with the 'invisible' recaptcha.

Not too sure if it would be best to create a new directive for this or modify the existing directive to handle both cases (since both deal with similar concerns).

mattmeye commented 7 years ago

yes, you are right,

more documentation is now online: https://developers.google.com/recaptcha/docs/invisible

TheSharpieOne commented 7 years ago

I was testing out the new invisible recaptcha on jsfiddle (https://jsfiddle.net/0x3c3goy/) and it has some interesting issues which could cause problems with normal use, not to mention how it would integrate into angular. Most people use ngSubmit or attach ngClick on button with callbacks when the form is submitted. This does not work well with the new invisible recaptcha. The user would need to use the onSuccess callback (just callback to recaptcha) which passes the token indicates both a successful recaptcha validation and a form submission. The user would not be able to tie into their existing form submission workflow as easily, forcing them to do it the "vcRecaptcha way".

Not to mention the docs say the API is subject to change, so any development at this point may go to waste

nickdnk commented 7 years ago

I would say +1 for this also. I just spent an entire night trying to get it to work with the existing code. Needless to say, I failed.

ghost commented 7 years ago

I was able to set up Invisible Recaptcha quite easily.

Firstly, set your button as the vc-recaptcha.

<button class="btn g-recaptcha"
    vc-recaptcha
    key="model.key"
    on-create="setWidgetId(widgetId)"
    on-success="setResponse(response)"
    on-expire="cbExpiration()">SIGN UP</button>

Then, ensure your $scope.model.key is an invisible recaptcha key, and simply call your signup function from $scope.setResponse, where $scope.response is the value to send back to your server.

$scope.model = {
    key: '** YOUR INVISIBLE RECAPTCHA KEY **'
};

$scope.setResponse = function (response) {
    $scope.response = response;
    $scope.signUp();
};

$scope.setWidgetId = function (widgetId) {
    $scope.widgetId = widgetId;
};

$scope.cbExpiration = function() {
    vcRecaptchaService.reload($scope.widgetId);
    $scope.response = null;
};

$scope.signUp = function() {
   // $http to your server to validate $scope.response
};

Edit: If you would like to disable the button (ng-disabled) if the form is invalid, you might have to write something into the directive. I was able to solve this quickly by keeping the button clickable, and doing a check in the signUp function. I simply reset the captcha by calling cbExpiration.

$scope.signUp = function() {

    if ($scope.form.$invalid) {
        $scope.cbExpiration();
        toastr.error('Please complete the form to continue.');
        return;
    };

    // $http to your server to validate $scope.response

};
Mr-Anonymous commented 7 years ago

I followed @bionetmarco said and he is right, its very easy to implement Invisible Recaptcha to the submit button directly. his instruction worked perfect and I am able to get this to work. So thank you @bionetmarco

However, when using the Invisible ReCaptcha, although the form submit works, I get this error in Chrome console when the button is clicked:

Uncaught TypeError: Cannot read property 'style' of null
    at gi (recaptcha__en.js:123)
    at Pn.<anonymous> (recaptcha__en.js:266)
gi @ recaptcha__en.js:123
(anonymous) @ recaptcha__en.js:266
blaketastic2 commented 7 years ago

@Mr-Anonymous I got around this problem with adding this to my page: `

`
EhsanKia commented 7 years ago

Works great, tiny problem I have, the first time you press, key is set and my signup is ran, but after that, the next time they press it again, nothing happens.

MaximeCheramy commented 7 years ago

I can confirm that bionetmarco's solution works, however I have the same issue than EhsanKia. Therefor, if there's an error in the form, the captcha is used once but the user can't submit it again. If I wait long enough I can submit again, sometimes after an error contacting reCaptcha server...

MaximeCheramy commented 7 years ago

I've found a fix:

In my form:

<div vc-recaptcha key="model.key" on-success="registerForReal(response)" size="invisible" required="false"></div>

In the submit function of the form:

    if (form.$valid) {
      vcRecaptchaService.reload($scope.widgetId);
      vcRecaptchaService.execute($scope.widgetId);
    }

The execute function is provided by https://github.com/VividCortex/angular-recaptcha/pull/188

jaeeunl commented 7 years ago

@MaximeCheramy Are you attaching the same attributes to a button too, or are you just using the div?

MaximeCheramy commented 7 years ago

I'm only using the div as explained in the recaptcha documentation: https://developers.google.com/recaptcha/docs/invisible#programmatic_execute This way, I trigger the captcha only when the form is valid. The way I'm using it with angular-recaptcha is probably a bit of a hack though. But it seems to work...

jaeeunl commented 7 years ago

@MaximeCheramy Thanks for your reply! For me, it gave an error saying that vcRecaptchaService.execute was not a function, but it worked when I replaced it with grecaptcha.execute().

ViieeS commented 7 years ago

Is it #188 working solution? When it will be merged?

@MaximeCheramy

if (form.$valid) {
      vcRecaptchaService.reload($scope.widgetId); // <-- Why do you reload it?
      vcRecaptchaService.execute($scope.widgetId);
}
androidovshchik commented 7 years ago

@ViieeS Yes. It works. I also wonder will it be merged But one unpleasant moment that there is no callback from library after form validation i need to get the response with captcha's code before sending request to my server

ViieeS commented 7 years ago

@mr-cpp I solved this based on trunk version.

Sequence:

validate->execute->onCallback->send->handleHttpResponce(ok->... | fail->reload)

<div
       vc-recaptcha
       required="false"
       size="invisible"
       on-create="setWidgetId(widgetId)"
       on-success="setResponse(response)"
       on-expire="cbExpiration()"></div>
$scope.data = {
    response: null,
    widgetId: null
};

$scope.setResponse = function (response) {
    $log.debug('Response available');
    $scope.data.response = response;
    send();
};

$scope.setWidgetId = function (widgetId) {
    $log.debug('Created widget ID: %s', widgetId);
    $scope.widgetId = widgetId;
};

$scope.cbExpiration = function () {
    $log.debug('Captcha expired. Resetting response object');
    vcRecaptchaService.reload($scope.data.widgetId);
    $scope.data.response = null;
};

$scope.submit = function () {
    if(formCtrl.$valid) // not needed in my case, because user can't submit form if it has invalid fields
        grecaptcha.execute($scope.data.widgetId);
};

var send = function () {
    // Http request, send $scope.data
    .then(function () {
        // onSucces...
    }).catch(function (errors) {
        // onFail...
        $scope.cbExpiration();
    });
};

But I have error after reload like @Mr-Anonymous has:

Uncaught TypeError: Cannot read property 'style' of null
    at gi (recaptcha__en.js:123)
    at Pn.<anonymous> (recaptcha__en.js:266)
gi @ recaptcha__en.js:123
(anonymous) @ recaptcha__en.js:266
PLPeeters commented 7 years ago

@ViieeS @Mr-Anonymous I found a workaround for the reload issue: I don't use the reload() function of the vcRecaptchaService and use an ngIf instead.

Just add ng-if="showRecaptcha" to the vc-recaptcha div, then change the cbExpiration() function to:

$scope.cbExpiration = function() {
    $scope.showRecaptcha = false;

    $timeout(function() {
        $scope.showRecaptcha = true;
    });
}

Don't forget to initialize $scope.showRecaptcha to true at the top of your controller.

ViieeS commented 7 years ago

@PLPeeters not bad) Where are the authors of repo?

P.S. Needs to merge #188

spengilley commented 7 years ago

Looks like #188 has now been merged into release 4.1.0

iambrosi commented 7 years ago

Done in #188. Closing now.

robertop87 commented 6 years ago

reCaptcha does not work under proxy :'(, any idea to fix this?

nickdnk commented 6 years ago

Proxy is not in the application layer, so it probably doesn’t have anything to do with this library.

On 28 Nov 2017, at 00.35, Luis Roberto Perez Rios notifications@github.com<mailto:notifications@github.com> wrote:

reCaptcah does not work under proxy :'(

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/VividCortex/angular-recaptcha/issues/174#issuecomment-347365068, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AIBYsnTmsNEZdvUmSSAu6uYTOYZ5D6Elks5s60dcgaJpZM4LMD8m.

sejas commented 6 years ago

You just need to call to grecaptcha.execute() Maybe with a little timeout:

   $timeout(function () {
        grecaptcha.execute()
     }, 1000)

You don't need to add a form tag in the html, just the vc-recaptcha:

      <div vc-recaptcha
           key="ctrl.key"
           size="invisible"
           on-create="ctrl.widgetId = widgetId"
           on-success="ctrl.onSuccess(response)">
      </div>