- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-14-2023 04:28 AM - edited ‎11-21-2023 01:29 AM
The requirement:
My organization has a public Service Portal in which both users and external can submit form. If the user is not logged in and submits the form, they want to Implement reCAPTCHA on these public portal forms.
On my PDI I have successfully created a widget that uses Google reCAPTCHA and provided it with the site and secret key. This is now working as seen in the screenshot. I next created a custom variable on a random Catalog Item and linked my previously created widget.
Question:
Now on the portal form, although the reCAPTCHA is there - the user can simply ignore and bypass the captcha and submit the form. How can I ensure that this is made mandatory, and prevents form submit unless successfully completed?
Catpcha Widget Code:
Body HTML template
<script src='https://www.google.com/recaptcha/api.js'></script>
<body>
<div class="g-recaptcha" data-sitekey="{{data.sitekey}}"></div>
<input type="button" value="Confirm" ng-click="c.checkCap()" />
</body>
Client Controller:
function() {
/* widget controller */
var c = this;
/**
* c.checkCap should be called via ng-click, and will return a boolean value,
* indicating whether the user is indeed validated to not be some sort of mechanized
* button-pushing device.
* If the user has performed no such validation, then an alert is shown, admonishing
* them for attempting to take over the human race.
*/
c.checkCap = function() {
var resp;
c.data.captchaSession = grecaptcha.getResponse();
if (!c.data.captchaSession) {
alert('You have not passed reCaptcha verification. \nPlease try again.');
resp = false;
}
c.server.update().then(function() {
var captchaResponse = c.data.captchaResponse;
if (captchaResponse) {
resp = isThisTrueOrWhat(captchaResponse);
}
});
grecaptcha.reset();
//Here, you might perform some action to allow or disallow submission based on the boolean value of the resp variable.
return resp;
}
}
function isThisTrueOrWhat(b) {
return ((typeof b == 'string') ? (b.toLowerCase() == 'true') : (b == true)); //all this just to properly return a bool in JS. THERE'S GOT TO BE A BETTER WAY!
}
Server Script
(function() {
/* populate the 'data' object */
/* e.g., data.table = $sp.getValue('table'); */
data.sitekey = gs.getProperty('recaptcha.site-key');
if (input) {
data.captchaResponse = null;
data.captchaSession = input.captchaSession;
try {
var RESTCAPTCHA = new sn_ws.RESTMessageV2();
RESTCAPTCHA.setHttpMethod('post');
RESTCAPTCHA.setEndpoint('https://www.google.com/recaptcha/api/siteverify');
RESTCAPTCHA.setQueryParameter('secret', gs.getProperty('recaptcha.secret-key'));
RESTCAPTCHA.setQueryParameter('response', data.captchaSession);
var captchaResponse = RESTCAPTCHA.execute();
if (captchaResponse.haveError()) {
gs.logError('Error in validating captcha response: ' + captchaResponse.getErrorMessage() + '. Status code: ' + captchaResponse.getStatusCode(), 'CaptchaAjax script include');
data.captchaResponse = false;
}
var successResponse = JSON.parse(captchaResponse.getBody()).success; //Relies on ES5 syntax. For ES3, use new JSON().decode(json_string);
data.captchaResponse = successResponse;
} catch (ex) {
gs.logError('Error in processing response from reCAPTCHA: ' + ex.message, 'CaptchaAjax script include');
data.captchaResponse = false;
}
}
})();
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-21-2023 02:45 AM - edited ‎11-21-2023 02:47 AM
Thanks for your help @mads2. However I managed to find the reason as to why the widget script was not updating the Catalog Item Form. It was actually an issue with my Widget Client Controller script not utilizing:
api.controller = function($scope) {}
For anyone else benefit in the future viewing this, with similar requirements; Implementing Google reCAPTCHA with ServiceNow Catalog Item Forms, below are the steps and code to follow:
1. Attain Google reCAPTCHA Site & Secret Key from: https://www.google.com/recaptcha/admin/create
The domains should correspond to each instance URL of your ServiceNow instance. So they will be a separate keys for dev | uat | live instances.
2. Insert the keys into as properties in the sys_properties table on ServiceNow
3. Create a Google reCAPTCHA widget in ServiceNow.
Within the client controller you will reference a boolean/ checkbox/ yes-no field that will update depending on if captcha is true.
Widget code:
Body HTML template
<script src='https://www.google.com/recaptcha/api.js'></script>
<body>
<div class="g-recaptcha" data-sitekey="{{data.sitekey}}"></div>
<input type="button" value="Confirm" ng-click="c.checkCap()" />
</body>
Server script
(function() {
data.sitekey = gs.getProperty('recaptcha.site-key');
if (input) {
data.captchaResponse = null;
data.captchaSession = input.captchaSession;
try {
var RESTCAPTCHA = new sn_ws.RESTMessageV2();
RESTCAPTCHA.setHttpMethod('post');
RESTCAPTCHA.setEndpoint('https://www.google.com/recaptcha/api/siteverify');
RESTCAPTCHA.setQueryParameter('secret', gs.getProperty('recaptcha.secret-key'));
RESTCAPTCHA.setQueryParameter('response', data.captchaSession);
var captchaResponse = RESTCAPTCHA.execute();
if (captchaResponse.haveError()) {
gs.logError('Error in validating captcha response: ' + captchaResponse.getErrorMessage() + '. Status code: ' + captchaResponse.getStatusCode(), 'CaptchaAjax script include');
data.captchaResponse = false;
}
var successResponse = JSON.parse(captchaResponse.getBody()).success;
data.captchaResponse = successResponse;
} catch (ex) {
gs.logError('Error in processing response from reCAPTCHA: ' + ex.message, 'CaptchaAjax script include');
data.captchaResponse = false;
}
}
})();
Client controller
api.controller = function($scope) {
/* widget controller */
var c = this;
/**
* c.checkCap should be called via ng-click, and will return a boolean value,
* indicating whether the user is validated and not a bot
* If the user has performed no such validation, then an alert is shown
*/
c.checkCap = function() {
var resp;
c.data.captchaSession = grecaptcha.getResponse();
if (!c.data.captchaSession) {
alert('You have not passed Captcha verification. \nPlease try again.');
resp = false;
}
c.server.update().then(function() {
var captchaResponse = c.data.captchaResponse;
if (captchaResponse) {
resp = confirmTrue(captchaResponse);
$scope.page.g_form.setValue('captcha_verification', 'Yes');
}
});
grecaptcha.reset();
return resp;
}
}
function confirmTrue(b) {
return ((typeof b == 'string') ? (b.toLowerCase() == 'true') : (b == true));
}
4. Create a Variable Set in which the Captcha will be stored.
Adding it to variable set will enable usability to any form in which Captcha is to be integrated.
Order: 10,000 (the make it generally at the bottom of most forms)
Variables:
line_break | Break Type field| (Only for cleanliness, as this way the captcha will be serrated from)
google_recaptcha | Custom with Label field | 'Please confirm the Captcha below to proceed.'
captcha_verification | Yes / No field | 'Captcha Verified?' (field will be hidden)
Catalog UI Polices:
a. Hide Google Captcha if Passed -
Simply, IF captcha_verification is YES, then HIDE google_recaptcha
Also, would suggest adding an info message in the Runs script section:
g_form.addInfoMessage('Thank you for confirming Captcha.');
b. Hide 'Captcha Verified' field -
No conditions, just simply hide captcha_verification always
Catalog Client Scripts:
a. Prevent form submission on Captcha fail -
onSubmit client script to prevent user by passing the captcha
function onSubmit() {
var captchaVerification = g_form.getValue('captcha_verification');
if (captchaVerification != 'Yes') {
g_form.addErrorMessage('You have not passed Captcha. Please try again');
g_form.submitted = false;
return false; //Abort the submission
}
}
Final product:
After the user presses confirm, the captcha disappears and user receives a message:
If the user attempts to ignore the captcha and submit the form, the user receives an error message:
_______________________________
That's all - I hope this helped. There was not much up to date resources in reCaptcha integration on ServiceNow community, YT etc., so i thought I would share this solution. Although this could certainly be refined, i.e. removal of the Confirm button (will leave you all with that one for yourselves 😉) - this certainly can serve as an MVP.
Please mark as helpful if this helped!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-17-2023 03:42 AM
From the embedded widget you can set variable values in the client controller with this script line: $scope.page.g_form.setValue('variable_name',[desired_value]);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-17-2023 07:54 AM
@mads2
I have tried doing so, but the Client controller script does not make any change to the portal..?
I tried created 3 field types on the portal and none of them were successful. Any ideas?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-21-2023 02:45 AM - edited ‎11-21-2023 02:47 AM
Thanks for your help @mads2. However I managed to find the reason as to why the widget script was not updating the Catalog Item Form. It was actually an issue with my Widget Client Controller script not utilizing:
api.controller = function($scope) {}
For anyone else benefit in the future viewing this, with similar requirements; Implementing Google reCAPTCHA with ServiceNow Catalog Item Forms, below are the steps and code to follow:
1. Attain Google reCAPTCHA Site & Secret Key from: https://www.google.com/recaptcha/admin/create
The domains should correspond to each instance URL of your ServiceNow instance. So they will be a separate keys for dev | uat | live instances.
2. Insert the keys into as properties in the sys_properties table on ServiceNow
3. Create a Google reCAPTCHA widget in ServiceNow.
Within the client controller you will reference a boolean/ checkbox/ yes-no field that will update depending on if captcha is true.
Widget code:
Body HTML template
<script src='https://www.google.com/recaptcha/api.js'></script>
<body>
<div class="g-recaptcha" data-sitekey="{{data.sitekey}}"></div>
<input type="button" value="Confirm" ng-click="c.checkCap()" />
</body>
Server script
(function() {
data.sitekey = gs.getProperty('recaptcha.site-key');
if (input) {
data.captchaResponse = null;
data.captchaSession = input.captchaSession;
try {
var RESTCAPTCHA = new sn_ws.RESTMessageV2();
RESTCAPTCHA.setHttpMethod('post');
RESTCAPTCHA.setEndpoint('https://www.google.com/recaptcha/api/siteverify');
RESTCAPTCHA.setQueryParameter('secret', gs.getProperty('recaptcha.secret-key'));
RESTCAPTCHA.setQueryParameter('response', data.captchaSession);
var captchaResponse = RESTCAPTCHA.execute();
if (captchaResponse.haveError()) {
gs.logError('Error in validating captcha response: ' + captchaResponse.getErrorMessage() + '. Status code: ' + captchaResponse.getStatusCode(), 'CaptchaAjax script include');
data.captchaResponse = false;
}
var successResponse = JSON.parse(captchaResponse.getBody()).success;
data.captchaResponse = successResponse;
} catch (ex) {
gs.logError('Error in processing response from reCAPTCHA: ' + ex.message, 'CaptchaAjax script include');
data.captchaResponse = false;
}
}
})();
Client controller
api.controller = function($scope) {
/* widget controller */
var c = this;
/**
* c.checkCap should be called via ng-click, and will return a boolean value,
* indicating whether the user is validated and not a bot
* If the user has performed no such validation, then an alert is shown
*/
c.checkCap = function() {
var resp;
c.data.captchaSession = grecaptcha.getResponse();
if (!c.data.captchaSession) {
alert('You have not passed Captcha verification. \nPlease try again.');
resp = false;
}
c.server.update().then(function() {
var captchaResponse = c.data.captchaResponse;
if (captchaResponse) {
resp = confirmTrue(captchaResponse);
$scope.page.g_form.setValue('captcha_verification', 'Yes');
}
});
grecaptcha.reset();
return resp;
}
}
function confirmTrue(b) {
return ((typeof b == 'string') ? (b.toLowerCase() == 'true') : (b == true));
}
4. Create a Variable Set in which the Captcha will be stored.
Adding it to variable set will enable usability to any form in which Captcha is to be integrated.
Order: 10,000 (the make it generally at the bottom of most forms)
Variables:
line_break | Break Type field| (Only for cleanliness, as this way the captcha will be serrated from)
google_recaptcha | Custom with Label field | 'Please confirm the Captcha below to proceed.'
captcha_verification | Yes / No field | 'Captcha Verified?' (field will be hidden)
Catalog UI Polices:
a. Hide Google Captcha if Passed -
Simply, IF captcha_verification is YES, then HIDE google_recaptcha
Also, would suggest adding an info message in the Runs script section:
g_form.addInfoMessage('Thank you for confirming Captcha.');
b. Hide 'Captcha Verified' field -
No conditions, just simply hide captcha_verification always
Catalog Client Scripts:
a. Prevent form submission on Captcha fail -
onSubmit client script to prevent user by passing the captcha
function onSubmit() {
var captchaVerification = g_form.getValue('captcha_verification');
if (captchaVerification != 'Yes') {
g_form.addErrorMessage('You have not passed Captcha. Please try again');
g_form.submitted = false;
return false; //Abort the submission
}
}
Final product:
After the user presses confirm, the captcha disappears and user receives a message:
If the user attempts to ignore the captcha and submit the form, the user receives an error message:
_______________________________
That's all - I hope this helped. There was not much up to date resources in reCaptcha integration on ServiceNow community, YT etc., so i thought I would share this solution. Although this could certainly be refined, i.e. removal of the Confirm button (will leave you all with that one for yourselves 😉) - this certainly can serve as an MVP.
Please mark as helpful if this helped!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎10-30-2024 12:50 AM
Hi @Community Alums , were you able to get the custom variable to show publicly? I could not set create role/read role as public. In fact, when custom variable is selected, the entire permission section is hidden.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎01-10-2024 03:49 AM
hi @Community Alums , do you know if this reCAPTCHA key will ever expire? If so, do you know what's the expiration frequency, e.g. It will expire after 3 months, etc?