Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Matt Barlow | jacker.io 164 posts 740 karma points c-trib
    Jul 28, 2017 @ 12:58
    Matt Barlow | jacker.io
    0

    RecaptchaV2 on forms with multiple pages - can't navigate between form pages.

    Hi,

    This is an awesome package, we have a slight issue when implementing the RecaptchaV2 on forms that have multiple pages, adding the Recaptcha prevents navigation between pages of the form.

    Have you spotted this before, any ideas how we can solve this?

    Thanks,

    Matt

  • Daniël Knippers 153 posts 1116 karma points MVP 2x c-trib
    Aug 01, 2017 @ 07:28
    Daniël Knippers
    0

    Hi Matt,

    I do not have much experience with multi page Umbraco Forms and have not seen this before. Does this happen with any fields that are mandatory and left empty when trying to navigate between pages? What about when using the default Recaptcha that comes with Forms? Does it still occur when the Recaptcha is checked or only when it's left empty?

    Regards, Daniël

  • Matt Barlow | jacker.io 164 posts 740 karma points c-trib
    Aug 08, 2017 @ 13:23
    Matt Barlow | jacker.io
    0

    Hi Daniel,

    Thanks for the reply, it's not to do with mandatory fields. I stepped through the source.

    In UmbracoEvents.cs there is:

    UmbracoFormsController.FormValidate += RecaptchaValidate;
    

    This adds the recaptcha check each time the form is validated, so when moving from one page to the next it fires. Then since the Recaptcha is on the 2nd page, the validation fails, and the navigation fails.

    I wonder how Umbraco.Forms does this with their version of the Recaptcha?, as this does allow navigation between pages.

    Probably need to update the code, so it only fires to validate if the page that is being validated contains a recaptcha control.

    Looks like this can be done via the FormValidationEventArgs.

  • Rob de Mercado 31 posts 147 karma points
    Oct 03, 2017 @ 16:19
    Rob de Mercado
    1

    I had exactly the same problem with the reCAPTCHA validating on a multi-step form. Fortunately, the contourPage div sits within a form, which has a FormStep hidden field, the value of which is the current form step.

    As all our forms (and I guess most others) have the reCAPTCHA right at the end of the form, it can safely be assumed (as in the code below) that the control is on the last step.

    <input name="FormStep" type="hidden" value="0">
    

    So, all you need to do is check to see if the current step is equal to the total number of steps, THEN do the reCAPTCHA validation, giving the following source change in UmbracoEvents.cs

    private void FormValidate(object sender, FormValidationEventArgs e)
        {
            //check to see which step we are at on the form (the last step will always contain the ReCaptcha control)
            int loop1 = 0;
            int currentStep = 0;
            String[] arr1 = e.Context.Request.Form.AllKeys;
            for (loop1 = 0; loop1 < arr1.Length; loop1++)
            {
                if (arr1[loop1] == "FormStep")
                {
                    currentStep = Convert.ToInt16(e.Context.Request.Form["FormStep"]) + 1;
                    break;
                }
            }
    
            //only try to validate a ReCaptcha control if we are on the last step
            if (currentStep == e.Form.Pages.Count)
            {
                JToken jToken = null;
                JToken jToken1 = null;
    
                LogHelper.Info<UmbracoFormsEvents>("FormValidate with ReCaptcha Running...", new Func<object>[0]);
                List<Field> list = (
                    from f in e.Form.AllFields
                    where f.FieldType.Name.Contains("GoogleReCaptcha")
                    select f).ToList<Field>();
                if (list.Any<Field>())
                {
                    Field field = list.FirstOrDefault<Field>();
                    HttpContext current = HttpContext.Current;
                    string setting = Configuration.GetSetting("RecaptchaPrivateKey");
                    if (setting != "")
                    {
                        string item = current.Request["g-recaptcha-response"];
                        string str = string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", setting, item);
                        bool flag = false;
                        List<string> strs = new List<string>();
                        //required to force TLS1.2 as TLS1.1 is disabled on the server
                        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
                        using (WebClient webClient = new WebClient())
                        {
                            JObject jObject = JObject.Parse(webClient.DownloadString(str));
                            if (jObject.TryGetValue("success", out jToken))
                            {
                                flag = Extensions.Value<bool>(jToken);
                            }
                            if (!jObject.TryGetValue("error-codes", out jToken1))
                            {
                                strs.Add("unknown-error");
                            }
                            else
                            {
                                JEnumerable<JToken> jEnumerable = jToken1.Children();
                                strs.AddRange(
                                    from child in (IEnumerable<JToken>)jEnumerable
                                    select Extensions.Value<string>(child));
                            }
                        }
                        if (!flag)
                        {
                            Controller controller = sender as Controller;
                            string str1 = ",";
                            foreach (string str2 in strs)
                            {
                                str1 = string.Concat(str1, ", ", str2);
                            }
                            str1 = str1.Replace(",,", "");
                            string str3 = string.Format("Recaptcha Verification Failed: {0}", str1);
                            if (field != null)
                            {
                                if (controller != null)
                                {
                                    controller.ModelState.AddModelError(field.Id.ToString(), str3);
                                }
                            }
                        }
                    }
                    else
                    {
                        LogHelper.Warn<UmbracoFormsEvents>("ERROR: ReCaptcha v.2 is missing the Secret Key - Please update the '/app_plugins/umbracoforms/umbracoforms.config' to include 'key=\"RecaptchaPrivateKey\"'", new Func<object>[0]);
                    }
                }
            }
        }
    

    You will notice one additional line which may come in handy. We disabled TLS1.1 on our server which stopped communication with the Google secure server, so I had to force the internet connection to use TLS1.2

    Finally I agree with Matt Barlow, it is an awesome package and saved me so much time.

  • Daniël Knippers 153 posts 1116 karma points MVP 2x c-trib
    Oct 04, 2017 @ 06:36
    Daniël Knippers
    1

    Thanks for your reply Rob, I'm sure your code will be of help. I'm sorry, this issue has not been a priority here as we have been busy with a million other things, but I see it's been far too long now since it was first reported. I will try my best to make some time for this next week to fix the Recaptcha on multi-page forms using the input provided here.

  • Matt Barlow | jacker.io 164 posts 740 karma points c-trib
    Oct 05, 2017 @ 14:42
    Matt Barlow | jacker.io
    100

    I fixed this by moving the logic from the Event into the Recaptcha V2 field type and override the ValidateField method.

    This means that you could validate per step in the form if you want too, as the validation is called between pages. So in PerplexRecaptcha.cs I added:

     public override IEnumerable<string> ValidateField(Form form, Field field, IEnumerable<object> postedValues, HttpContextBase context)
        {
            var secretKey = Umbraco.Forms.Core.Configuration.GetSetting("RecaptchaPrivateKey");
    
            if (string.IsNullOrEmpty(secretKey))
            {
                // just return the error message
                LogHelper.Warn<UmbracoEvents>("ERROR: ReCaptcha v.2 is missing the Secret Key - Please update the '/app_plugins/umbracoforms/umbracoforms.config' to include 'key=\"RecaptchaPrivateKey\"'");
                return new[] {ErrorMessage};
            }
    
            var reCaptchaResponse = context.Request["g-recaptcha-response"];
            var url = $"https://www.google.com/recaptcha/api/siteverify?secret={secretKey}&response={reCaptchaResponse}";
    
            var isSuccess = false;
            var errorCodes = new List<string>();
    
            using (var client = new WebClient())
            {
                var response = client.DownloadString(url);
    
                var responseParsed = JObject.Parse(response);
    
                //Get Success Status
                JToken sucessToken;
                var sucessFound = responseParsed.TryGetValue("success", out sucessToken);
                if (sucessFound)
                {
                    isSuccess = sucessToken.Value<bool>();
                }
    
                //Get Error codes
                JToken errorsToken;
                var errorsFound = responseParsed.TryGetValue("error-codes", out errorsToken);
                if (errorsFound)
                {
                    var errorsChildren = errorsToken.Children();
                    errorCodes.AddRange(errorsChildren.Select(child => child.Value<string>()));
    
    
                }
                else
                {
                    errorCodes.Add("unknown-error");
                }
            }
    
            if (isSuccess)
            {
                return Enumerable.Empty<string>();
            }
    
            return new[] { ErrorMessage }; 
        }
    

    and I removed from /code/UmbracoEvents.cs

    UmbracoFormsController.FormValidate += RecaptchaValidate;
    

    and also removed the associated method.

     private void RecaptchaValidate(object sender, FormValidationEventArgs e)
    
  • Daniël Knippers 153 posts 1116 karma points MVP 2x c-trib
    Oct 13, 2017 @ 15:12
    Daniël Knippers
    0

    Hi Rob & Matt -- and others :-),

    I just uploaded a new version (1.8) which incorporates Matt's fix for this issue. ValidateField indeed seems the way to go for this one, thanks for your input!

    -- Daniël

  • ECL 7 posts 37 karma points
    May 10, 2018 @ 14:23
    ECL
    0

    I am having this issue on a multi-page form:

    Umbraco Forms 6.0.6

    Umbraco version 7.7.8 assembly: 1.0.6582.14881

    Perplex 1.8.2

    Works OK on page 1 - when applied to the last page, I get the following error when I try to progress form Page 1

    The operation has timed out
    
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 
    
    The operation has timed out
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 
    
    Exception Details: System.Net.WebException: The operation has timed out
    
    Source Error: 
    
    An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
    
    Stack Trace: 
    
    
    [WebException: The operation has timed out]
       System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest& request) +365
       System.Net.WebClient.DownloadString(Uri address) +111
       PerplexUmbraco.Forms.Code.UmbracoEvents.RecaptchaValidate(Object sender, FormValidationEventArgs e) +572
       Umbraco.Forms.Web.Controllers.UmbracoFormsController.ValidateFormState(FormViewModel model, Form form, HttpContextBase context, Boolean captchaIsValid) +1719
       Umbraco.Forms.Web.Controllers.UmbracoFormsController.HandleForm(FormViewModel model, Boolean captchaIsValid) +348
       lambda_method(Closure , ControllerBase , Object[] ) +195
       System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +209
       System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +35
       System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +39
       System.Web.Mvc.Async.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult) +67
       System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +42
       System.Web.Mvc.Async.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d() +72
       System.Web.Mvc.Async.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() +385
       System.Web.Mvc.Async.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() +385
       System.Web.Mvc.Async.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() +385
       System.Web.Mvc.Async.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() +385
       System.Web.Mvc.Async.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() +385
       System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +42
       System.Web.Mvc.Async.<>c__DisplayClass2b.<BeginInvokeAction>b__1c() +30
       System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult) +185
       System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +38
       System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +29
       System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +65
       System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +52
       System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +36
       System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +38
       System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +43
       System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +65
       System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +38
       System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +393
       System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +195
       System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +128
    
  • Daniël Knippers 153 posts 1116 karma points MVP 2x c-trib
    May 21, 2018 @ 12:10
    Daniël Knippers
    0

    Hi ECL,

    Did it also work on page 1 when you navigated or submitted the form? I'm asking because it seems the Network Request to Google timed out (according to the exception), so I wonder if your PC could simply (temporarily) not reach the Google server for the validation to occur. If that was indeed the case the Recaptcha should never actually work. It would render, but the validation would always throw this exception.

    And do I understand correctly you get this error when the Recaptcha is on the last page (let's say page 3), and you navigate from page 1 to 2? I would imagine the Recaptcha validation should not trigger at all at the point. It should only trigger when submitting the whole form and/or when you navigate from page 3 to some other page (perhaps only when going forward but not sure). Our package does not control when validation occurs, as you can see in the code of Matt above we simply implement a ValidateField method to do the validation but this is called by Umbraco.

    Regards, Daniël

  • Matt Barlow | jacker.io 164 posts 740 karma points c-trib
    Oct 15, 2017 @ 12:53
    Matt Barlow | jacker.io
    0

    Awesome Daniel. thanks. :)

Please Sign in or register to post replies

Write your reply to:

Draft