Has anyone implemented reCAPTCHA?

  • 1
  • Question
  • Updated 2 months ago
  • Answered
Trying to implement reCAPTCHA on a force.com site. Has anyone done this? 
Photo of Josef Lagorio

Josef Lagorio

  • 2,832 Points 2k badge 2x thumb

Posted 8 months ago

  • 1
Photo of Peter Hale

Peter Hale, Employee

  • 330 Points 250 badge 2x thumb
There is a way to implement ReCaptcha on a Skuid page using a Field Editor, some JS, and a template below the field editor.  There are a few tricks that need to be updated for it to work properly:
1.  When someone updates any field that has a popup, such as date fields or reference fields, the ReCaptcha piece goes away.  It needs to be reset using JS
2.  We need to know when the user successfully validates ReCaptcha, so the save button can be enabled

Here's how it can be implemented.

1.  Put a template below the Field Editor that contains the following:
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit";
    async defer>
</script>
2. Have an inline Javascript snippet that contains the following:
var captchaCallback = function(data) {
    var model = skuid.model.getModel("CaptchaValidated");
    model.updateRow(model.getFirstRow(), {isValid:true});
}
var onloadCallback = function() {
    grecaptcha.render('recaptchaElement', {
      'sitekey' : '[your-site-key]',
      'callback': captchaCallback
    });
};
Make sure to replace [your-site-code] with your own ReCaptcha site key. The first method is called when the user successfully validates, and it sets a field "isValid" in a UI-only model to true.  I put a save button in a button set and in the rendering tab, made the button disabled until this flag is true:


3.  Add a template to the Field Editor to display the ReCaptcha component.  The template should contain:
<div id="recaptchaElement"></div>
4.  Have another JS Snippet that you can call when a row is updated.  The snippet should have the following code:
var params = arguments[0],
$ = skuid.$;

onloadCallback();
5.  When any row is updated in your model, call this snippet:


The page I did looks like this:
Photo of Peter Hale

Peter Hale, Employee

  • 330 Points 250 badge 2x thumb
For reference, here's the XML of the page I used to demonstrate ReCaptcha:
<skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="true" useviewportmeta="true" showheader="true">
    <models>
        <model id="NewTask" limit="1" query="false" createrowifnonefound="true" datasource="salesforce" sobject="Task">
            <fields>
                <field id="AccountId"/>
                <field id="Account.Name"/>
                <field id="CallType"/>
                <field id="ActivityDate"/>
                <field id="WhatId"/>
                <field id="What.Name"/>
            </fields>
            <conditions/>
            <actions>
                <action>
                    <actions>
                        <action type="custom" snippet="recaptchaRefresh"/>
                    </actions>
                    <events>
                        <event>row.updated</event>
                    </events>
                </action>
            </actions>
        </model>
        <model id="CaptchaValidated" query="true" createrowifnonefound="true" datasource="Ui-Only" processonclient="true">
            <fields>
                <field id="isValid" displaytype="BOOLEAN" ogdisplaytype="TEXT"/>
            </fields>
            <conditions/>
            <actions/>
        </model>
    </models>
    <components>
        <buttonset model="CaptchaValidated" uniqueid="sk-Wht-1313">
            <buttons>
                <button type="multi" label="Save" uniqueid="sk-Wht-1318" icon="fa-check" window="self">
                    <renderconditions logictype="and"/>
                    <enableconditions logictype="and">
                        <condition type="fieldvalue" operator="=" enclosevalueinquotes="false" fieldmodel="CaptchaValidated" sourcetype="fieldvalue" field="isValid" value="true"/>
                    </enableconditions>
                    <actions>
                        <action type="save">
                            <models>
                                <model>NewTask</model>
                                <model>CaptchaValidated</model>
                            </models>
                        </action>
                    </actions>
                </button>
                <button type="cancel" label="Cancel" uniqueid="sk-Wht-1322" window="self">
                    <models>
                        <model>NewTask</model>
                    </models>
                    <hotkeys/>
                    <renderconditions logictype="and"/>
                    <enableconditions/>
                </button>
            </buttons>
        </buttonset>
        <basicfieldeditor showheader="true" showsavecancel="false" showerrorsinline="true" model="NewTask" uniqueid="sk-Wht-253" mode="edit">
            <columns>
                <column width="50%">
                    <sections>
                        <section title="Section A" collapsible="no" showheader="false">
                            <fields>
                                <field uniqueid="sk-Wht-290" id="AccountId"/>
                                <field uniqueid="sk-Wht-291" id="CallType"/>
                                <field uniqueid="sk-Wht-292" id="ActivityDate"/>
                                <field uniqueid="sk-Wht-293" id="WhatId"/>
                            </fields>
                        </section>
                    </sections>
                </column>
                <column width="50%">
                    <sections>
                        <section title="Section B" collapsible="no" showheader="false">
                            <fields>
                                <field uniqueid="sk-Wht-306" type="COMBO" editmodebehavior="autopopup" readonly="true">
                                    <label>Re-Captcha</label>
                                    <renderconditions logictype="and" onhidedatabehavior="keep"/>
                                    <enableconditions/>
                                    <template>&lt;div id="recaptchaElement"&gt;&lt;/div&gt;</template>
                                </field>
                            </fields>
                        </section>
                    </sections>
                </column>
            </columns>
        </basicfieldeditor>
        <template multiple="false" uniqueid="sk-Wht-266" allowhtml="true">
            <contents>&lt;script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&amp;render=explicit";
    async defer&gt;
&lt;/script&gt;</contents>
        </template>
    </components>
    <resources>
        <labels/>
        <javascript>
            <jsitem location="inline" name="recaptcha" cachelocation="false" url="">
var captchaCallback = function(data) {
    var model = skuid.model.getModel("CaptchaValidated");
    model.updateRow(model.getFirstRow(), {isValid:true});
}

var onloadCallback = function() {
    grecaptcha.render('recaptchaElement', {
      'sitekey' : '6LfXckwUAAAAAPZtN95U_W4UFizPvSCZeC7WUKSc',
      'callback': captchaCallback
    });
};
</jsitem>
            <jsitem location="inlinesnippet" name="recaptchaRefresh" cachelocation="false">var params = arguments[0],
$ = skuid.$;

onloadCallback();</jsitem>
        </javascript>
        <css/>
        <actionsequences uniqueid="sk-Wht-282">
            <actionsequence id="c496997b-2e33-49de-82a9-e94178938559" label="ReCaptcha Fired" type="event-triggered" event-scope="component" event-name="captchaFired" uniqueid="sk-Wht-1043">
                <description/>
                <actions>
                    <action type="blockUI" message="Done?" timeout="3000"/>
                </actions>
            </actionsequence>
        </actionsequences>
    </resources>
    <styles>
        <styleitem type="background" bgtype="none"/>
    </styles>
</skuidpage>
Photo of Or Cingilli

Or Cingilli

  • 104 Points 100 badge 2x thumb
Peter,

In trying to follow your example, I keep getting this error:

There was a problem rendering a component of type basicfieldeditor: grecaptcha is not defined

The page loads fine if I remove the template field and script.

I've compared my XML to yours and I do not see what could be causing this issue.

There are a couple fields of type picklist that are required on the Salesforce object. Could this be affecting the recaptcha script?

Thanks,

Or




Photo of Or Cingilli

Or Cingilli

  • 104 Points 100 badge 2x thumb
Looks the cause of the error is an action that is set to fire when any model row is updated and the field is a Salesforce picklist that is required at field level. When the page loads, it looks like it is thinking the model has been updated and tries calling recaptchaRefresh before the fields load on the page. 

Not sure how to resolve though. Your sample is working correctly, except your sample does not have a Salesforce picklist that is required. 
(Edited)
Photo of Mark DeSimone

Mark DeSimone, Official Rep

  • 11,030 Points 10k badge 2x thumb
Hi Or,

It sounds like you may only need to trigger the "recaptchaRefresh" snippet when someone updates any field that has a popup, such as date fields or reference fields. Can you adjust your model action so that it only triggers the snippet when those fields are updated, instead of triggering it for any field update?
Photo of Mark DeSimone

Mark DeSimone, Official Rep

  • 11,030 Points 10k badge 2x thumb
Hi Or, I wanted to check in and see if my suggestion was useful, or if you've been able to get this working.