ahammoud
Tera Guru

Hello Community,

I had client asking me to add Google reCaptcha on their Record Producer on the Service Portal and allowing anonymous users to submit Incidents. However, they wanted to disable the Submit button on the page if they are NOT verified by the reCaptcha or they NOT authenticated. 

There's also an interesting article by Göran on adding reCaptcha in the Portal.

I wanted to keep the solution simple allowing both anonymous and authenticated users to use the same page.

If the Captcha token is expired or the answer is wrong it must disable the Submit button again, until the user passes the reCaptcha validation.

1. Create a reCaptcha Widget, give it an id and the following:

  • Body HTML; the submit Button visbility is based on the captach Response :
<!-- Begin Captcha code -->
<!-- This widget is in place to force non-athenticated users to pass Captcha validation, it works in correlation with Widget "udes-widget-sc-cat-item-v2"
The Submit button on the Page will remain disabled until it validates the Captcha response. Alternatively You can broadcast an event between the widgets to disable/enable the Submit Button, although Not recommended -->

<div ng-if="!data.logged_in"> 
<script></script>

  <!--
<script>
  function checkCap() {
    alert(grecaptcha.getResponse());
    }
</script>
-->
  
<body>  
  <div class="g-recaptcha" data-sitekey="{{data.sitekey}}" data-callback="captchaCallback" data-expired-callback="captchaExpiredCallback"></div>
  <!-- Enlever le commentaire ici si vous voulez tester votre clé <input type="button" value="Test" onClick="checkCap()" /> -->
  
  <script>
  function captchaCallback() {
    document.getElementById("submit-udes-button").disabled = false;
    //captchaClientCallback();
  }
    
  function captchaExpiredCallback() {
    document.getElementById("submit-udes-button").disabled = true;
  }
  </script>  
</body>  
</div>
<!-- End of Captcha code -->
  • Server Script
(function() {
 data.sitekey = gs.getProperty('property of your API Captacha V2 Key');
 data.logged_in = gs.isLoggedIn();
})();
  • Client Controller
function($rootScope) {
		
//return MyAlert;
	
captchaClientCallback = function() {
		
//return MyAlert;
 var c = this;
//console.log("Successfuly validated by Google reCaptcha");
			var passedCaptcha = true;
 $rootScope.$broadcast('customEvent', passedCaptcha);
 //}

		};
}

 

2. Clone the Widget "widget-sc-cat-item-v2" this widget will be used on the sc_cat_item page which is showing the record Producer form, or any record producer of choice. On the Cloned Widget :

  • Modifying the following HTML part on line 181 from this code:
<div class="form-group m-b-xs" ng-if="c.options.native_mobile != 'true'">
            <button sp-ellipsis-tooltip sp-ellipsis-tooltip-title="{{submitButtonMsg}} ng-if="::c.showOrderNowButton()" tabindex="0" name="submit" id="submit-btn" ng-disabled="disableControls()" ng-click="triggerOnSubmit()" class="btn btn-primary btn-block text-overflow-ellipsis">{{submitButtonMsg}}</button>
            <span ng-if="submitting" style="padding-left:4px">${Submitting...}</span>
            <span ng-if="validating" style="padding-left:4px">${Validating...}</span>
          </div>
  • We want to add an ID to the button element, so it will look like this:
<div class="form-group m-b-xs" ng-if="c.options.native_mobile != 'true'">
            <button id="submit-udes-button" ng-if="::c.showOrderNowButton()" tabindex="0" name="submit" ng-disabled="disableControls()" ng-click="triggerOnSubmit()" class="btn btn-primary btn-block">{{submitButtonMsg}}</button>
            <span ng-if="submitting" style="padding-left:4px">${Submitting...}</span>
            <span ng-if="validating" style="padding-left:4px">${Validating...}</span>
          </div>
  • On the Server script, add the following code before anything to check if the user is authenticated 
	//Check if user is logged and and Hide Submit Button
	// See disableControls function in Client Side
	var loggedIn = gs.isLoggedIn();
	data.logged_in = true;
	
	if (!loggedIn)
	data.logged_in = false;
		
	var localInput = input; //to safeguard pullution of "input" via BR or other scripts
  • Client Control: on line 12 modify the code to the following, by adding logged in validation to disable the button:
$scope.disableControls = function(){
		return $scope.submitting || $scope.submitted || c.data.isPreview || !c.data.logged_in;
	}

3. Position your Widgets on the page and make sure it is Public and so is your Portal:

find_real_file.png

 

And here is the Final Product:

If the user is not authenticated and have not passed the Captacha Validation

find_real_file.png

 

 

After passing the reCaptcha validation:

 

find_real_file.png

Comments
TStark
Kilo Sage

Hi @ahammoud 

 

I tried following your steps and I've made everything public, but the reCAPTCHA is not showing up at all for me. I feel like there's something I'm missing that you haven't provided in your post. One thing I didn't see was any reference to https://www.google.com/recaptcha/api.js .  I tried adding that to the HTML part of the widget and no luck. Below is a screenshot of my public catalog item.

 

AJ27_0-1671317671657.png

 

Richard P
Mega Guru

@TStark 
try this in your html of the widget, 


<script src='https://www.google.com/recaptcha/api.js'></script>

 

<!-- Begin Captcha code -->
<!-- This widget is in place to force non-athenticated users to pass Captcha validation, it works in correlation with Widget "udes-widget-sc-cat-item-v2"
The Submit button on the Page will remain disabled until it validates the Captcha response. Alternatively You can broadcast an event between the widgets to disable/enable the Submit Button, although Not recommended -->

<div ng-if="!data.logged_in">
<script></script>

<script>
function checkCap() {
alert(grecaptcha.getResponse());
}
</script>

 

<div class="g-recaptcha" data-sitekey="{{data.sitekey}}" data-callback="captchaCallback" data-expired-callback="captchaExpiredCallback"></div>
<!-- Enlever le commentaire ici si vous voulez tester votre clé <input type="button" value="Test" onClick="checkCap()" /> -->

<script>
function captchaCallback() {
document.getElementById("submit-udes-button").disabled = false;
//captchaClientCallback();
}

function captchaExpiredCallback() {
document.getElementById("submit-udes-button").disabled = true;
}
</script>
</body>
</div>
<!-- End of Captcha code -->

TStark
Kilo Sage

Thanks @Richard P  but I ended up going a different route that worked. See my poste here --> https://www.servicenow.com/community/itsm-forum/the-google-recaptcha-dilemma/td-p/2426410#M484655

 

Thanks,
AJ

bigbroken
Tera Explorer

I appreciate this tutorial lots of good info in there.

But one important note is that this is all implemented on client side, so its trivial to bypass the verification check by enabling the button. 

 

ahammoud
Tera Guru

hello @bigbroken even if you try to modify the bypass the by enabling the button on the UI, the button is NOT visible in the Element Console

PeterdeBock VU
Tera Contributor

hi @ahammoud ,

 

Awesome! Thx for sharing this. Today I incorporated it in our Public portal for a couple of public catalog item forms. 

I had an issue with the "HTML template" code in the widget, I noticed that you posted a fix, though in the fix there is some code for the <body>  missing. After combining it with the previous post it did the trick!

 

HTML template Code I used;

<!-- Begin Captcha code -->
<!-- This widget is in place to force non-athenticated users to pass Captcha validation, it works in correlation with Widget "udes-widget-sc-cat-item-v2"
The Submit button on the Page will remain disabled until it validates the Captcha response. Alternatively You can broadcast an event between the widgets to disable/enable the Submit Button, although Not recommended -->

<div ng-if="!data.logged_in"> 
<script src='https://www.google.com/recaptcha/api.js'></script>

  <!--
<script>
  function checkCap() {
    alert(grecaptcha.getResponse());
    }
</script>
-->
  
<body>  
  
  
  <div class="g-recaptcha" data-sitekey="{{data.sitekey}}" data-callback="captchaCallback" data-expired-callback="captchaExpiredCallback"></div>
  <!-- Enlever le commentaire ici si vous voulez tester votre clé <input type="button" value="Test" onClick="checkCap()" /> -->
  
  <script>
  function captchaCallback() {
    document.getElementById("submit-udes-button").disabled = false;
    //captchaClientCallback();
  }
    
  function captchaExpiredCallback() {
    document.getElementById("submit-udes-button").disabled = true;
  }
  </script>  
</body>  
</div>
<!-- End of Captcha code -->

 

Another issue I faced is that the Submit button did not become readonly. It was caused by modifying another "showOrderNowButton" in my customer's already customized Catalog widget. So if other people face the same; just use your browser Inspect to verify which Submit button you need to customize by adding the id="submit-udes-button" and ng-if="::c.showOrderNowButton()",

 

<button id="submit-udes-button" ng-if="::c.showOrderNowButton()" tabindex="0" name="submit" ng-disabled="disableControls()" ng-click="triggerOnSubmit()" class="btn btn-primary btn-block">{{submitButtonMsg}}</button>

 

PeterdeBockVU_0-1739213347333.png

 

regards, Peter

Version history
Last update:
‎12-16-2021 01:11 PM
Updated by: