GoogleCloudPlatform / recaptcha-enterprise-mobile-sdk

Apache License 2.0
29 stars 5 forks source link

Recaptcha produces invalid token on iOS when used within a library #113

Open lemcoder opened 3 months ago

lemcoder commented 3 months ago

Describe the bug

I am using reCaptcha enterprise SDK from within my own SDK. It is written in Kotlin Multiplatform and compiled to objectiveC. Recaptcha client returns the token but it is invalid. It does not contain information about bundleId.

The generated token:

03AFcWeA5sjjAE6MnGAdkphd5NFg1IOZa--czGOHZGDAvINIQ8-vZj5zlF_2E0FNZKl-6QQm41sKNMw4xkqdUcs_bZKR6KhL25ngBYSCdVSr4AJfzpyK1znMxQcrYvx6xOSiZ1IzkYlg4xlLUvAqFKtzgtaiikxmdmPzliOH2rPf5tA0-1Sj54p1VTlbsyCEl-WwR0neKMl0r4_U6QpzeShUFsAWA6POolJKRgRJs8T_iMV-tenziXtGEU3tGc12SeklriDA9IdC7WV60IMm9hjjmGFirrCQLwHWNml3FtyoKuzjV5n79PAkmclBa4LLHijCItwZsa-s3LaLsJ5dsNJlK-xMI5s5YTzat297oS6kZdm8Y0sEwRrG2ZTlrIeZB6YMdfxDkI-t7fnp38UXfkaHYlKkcMDoB1ur-eKEj1FoC_vOf5iHRz1_NhoYvJpfwruWPQ-_acG1Dn_an5j4scl4xLjA3iH24PtXGJEmEzti9CeqvkmpROcTkGUgShrHlcZ5xG71v1dkfXeu1kxAAdKetlXzm9TR5fjXmuDIn3qPiKMi7Ui-gqRZcT_jHXhZc_1n8ni3ZjgDb2rGecJxBDliQYwkqS2bVIZZlMxmwiqRzO3fTsNcaV6EHw5tfI-bT97OyhXvvLtbXPIz-mR9nVDdRyixZhQyFawk7tmHChDuUbLnwvOnmWZGbo4RYInJn-HrVlmoM3JrjCDtOazaxeX2jew0jiCazBl0cld3VYWEyykX9q3Q-jXpK0Vhj3gzPhK6QZor69WajyLhtfBspADjDEgZr6nCVxQC9PHiNSYOWW9JAZxaSk9YapMU1bMEbn5ZJWhVEh3EF7fCY_vVuWI8dGH26t0DZzdUyZAe55_ZQFAiI-grWuuZ1OykBkZrT7tAa_j_k08bHXLGoNnik7Dw6gU6yM0CP-v0F2MR-ByygUOEA0s1xiih79840oJkGCKaZHSSncOz2QBqKhu0qOaQS1aSnBEZVo0fGOdS

reCAPTCHA Site Key

6Lei-PIpAAAAAFHkl5Q4KMuFr83lEJg2Mip06V70

Integration Method

Select the method used to integrate with reCAPTCHA Mobile.

SDK Version (e.g. 18.0.1):

To Reproduce

Steps to reproduce the behavior:

Cannot create a minimal example. You would have to use the SDK from objective-C and then wrap that usage in another library as this is basically what Kotlin compiler does.

Expected behavior

Return a valid key

Screenshots

If applicable, add screenshots to help explain your problem.

Xcode version for iOS (please complete the following information):

Device (please complete the following information):

Additional context

Works fine when used on the same device from Swift. Perhaps the SDK cannot gain access to some bundle info when used outside of the ViewController?

walterjgsp commented 3 months ago

Thanks for the report @lemcoder, we found this bug about bundleId and KMM https://youtrack.jetbrains.com/issue/KT-56152. Could you try the suggestion to specify the bundleId explicitly?

lemcoder commented 3 months ago

I've tried the provided solution but unfortunately without success. The generated token is still MALFORMED. Also I get those errors in the console after calling the reCaptcha client (don't know if it is related):

Warning: -[BETextInput attributedMarkedText] is unimplemented
nw_application_id_create_self NECP_CLIENT_ACTION_GET_SIGNED_CLIENT_ID [80: Authentication error]
Failed to resolve host network app id

It returns without exception but the token is invalid

Maybe there is a way to pass in the bundleId to reCaptcha client somehow? Or maybe I could override some method or sth

walterjgsp commented 3 months ago

What's the Xcode version being used? And what's the SDK version of reCaptcha that's being used? Could you try with both reCaptcha 18.4.1 and 18.5.1 to see if the error persist?

lemcoder commented 3 months ago

the Xcode version is Version 15.3 (15E204a) Recaptcha version is the latest. I will try downgrading and will let you know

lemcoder commented 3 months ago

So downgrading the version did not change much. Here is the token generated by 18.4.1:

03AFcWeA4rSpMahssBOOebRVzSSN7KTrVkAjMoZk2LTLhYQdoV7P0ge2O0Yv7BDrHeN9y7MsRnVq-ZBw3whYhIu6C8td9B3zXzIsaDT7fbObDieBhxjr8GRJCATLmpdI8Yj6G0ox0wZRw8f6nOV0fLypx_lF35Q5r7_SeSdXLIyr57ODGanHMLaDNPLzmn7joE85XfkA9Wz_-mdn8PEXmqea2Or1TN2rWK7riSGgEMbhAmqDtONsV41P0x-2uJiPUZXhp7IshiR73TMopvOl6N7xSAvb1bVQn-UKd2XtF_vi7G-VSTDCZBx3B2JBnb1eFGSsRYZ6eFpCTCyVKUxqpFAPj_OUE2vAxTS4ehoFeQtjeyVbPloOkE4vfM1jFfyWI7Stm_KjDdpVqEbI3Ja-xm0qaTQ8iKKnNrC1BvI7JgXtW1sNc0A_KgIZw4tz40-MD9XPGWpuc08RA2VRdTcpefdVTpu_tu9cum7APc4qmy9AnDWH2NJYm8YMwt3-D3LbBgNC7Hq5k8ykPbjPImL_hjox_b8DfwlDQ-vZ-jxoSs1sbCeeTYTHc14Zgz0lIiF6FXzz2-ZkBcj3UBou1SYMsW-AjY_ANjWjDKsypGGyq07TabMRtEopzywP1v_IwP-_e0-HZEKkKjeHdc2VFQqPHmM3kmp50Mzn95DIqwB_xTY2BT0V5aLdGU9BRjyXw1wv6bbCiWz4o6nhD0BxYKAc1zdGkovytKxOU0BSY9kmv8GpouNZNm2mfYVe5bu_khHygPruPQ6G-UTeXJNN1K8x9yXhONdyV4VhZ2SNDE-2Me7yrUYLWNNfGx89e8_dny-TryQiJOnfRYqJKTvUxNnTS8p9FMQyTziIJ0BGW2kPG_5kmzDhC8e-6paU8pHBCROYJ6n-NJorAVhZAtTXbVrv8rbtQO-AUiLkrRmPJqWb5yDkT70cN9o6i1qCiTiVbG5UVreW1Ghtjrn7_21hOROrNh8fa_1J4yyE_5RKRMXv

And here the one generated by 18.5.0:

03AFcWeA41pXxf_2FwURAQJs31AqN3ieYzA-XFsJ-54FDHvPFJPJiQKZ-7znDL-UZmvwzaG3vof3uZ-JVsJBz5RZsrYhsCTKpEJI7fykJGXFJD0dCEf4fOW_Pcx-1dXz15YE-_P2aqUpWEAQOyOLhzbzRmqQjdrFgD4h_2VIf10XWlImRjiqeWD0xlRHT9XJ1DYWCjdZmNJj0ZdwW_qWC338bn1PlvJvjOom1lxo5w6__qd0N1sxO6lAIsjunZMFtQdg2CkyVyOJvUqk62QUadehoiKOatN0B0d7UJcB0i-eIEPU7zTZ5B9anGgfp70YvI3Zmvx5fP1XOouZUhisAPie2yek70uTp_msyvClcz6cB-VgW4PqSvfEW1zRsAFpuI03lQYdwKPXuASDWqV398I9UV2C-gwtnlS1FhCGAB_yT77A1U0Bj2bWLXYdhMS5hKvnApKEgTNK5GsDlFNAocofEwMgrXPnzIR53ijL-LiRkKTuWufRJ_O76VxzhmUtHKZ-VRywMlEWXNp5J86Iq8hOizm24gSfTpyRjwz0MHAF7KErz4wK60ADininkvSOveJLj7S7LH0YJ91aKA7ymWYn7qF6pCVkX0JdLKMNVo7On3sQdaQaDBI1iDHQddKtsC1vXVQkLhicXPJS1S_8oTkf0nZdFP7Q4B4LMyd3h03PAMhG8k9IA6OCvy9679kEh6aDsiHzqThTgBjdI1xFV-HCVLiKW682VcS0_cbEocpGzDHHi9ZV1df2tr62IjNDoLO5krxaUidE4LA5N2KCX76gWdpfib_Aftnlc9fYmn242BdGGtkZIe2Xg4zUa3PXlHkkdQgp608neNPz4_u6D8SlXebHNqVwTVtkWbq2FgiCmFXVON6LHi3GOK4hZy0E2I1Qx6PKn3PjDqDyFDZeX46byNDVWeXk8WrSa3eCkDFn93WPl4S65qJMjWTEtFT9qVbdV8fwHLo7VedldxfC_LZ0Dx-Aw-UTi3ZlF2gq
mcorner commented 3 months ago

@lemcoder let's back up a little. When you say malformed, do you mean you get an error from create assessment or the result is just missing the bundle id? Or something else?

lemcoder commented 3 months ago

I mean the google service returns MALFORMED as invalidReason when we try to verify the token (on backend):

  "tokenProperties": {
    "valid": false,
    "invalidReason": "MALFORMED",
    "hostname": "",
    "androidPackageName": "",
    "iosBundleId": "",
    "action": "",
    "createTime": "1970-01-01T00:00:00Z"
  }
mcorner commented 3 months ago

This generally points to a truncated token. Is there a chance you aren't sending the entire token to your backend? This can happen if you put it in a get parameter rather than a post body.

lemcoder commented 3 months ago

I've tried to send the token that is generated using Swift (like pointed in docs here). And the validation works. So this will not be a problem with backend but rather with the token generation itself.

Also the token generated in Swift is much longer than the one that I get when calling Recaptcha within my SDK.

Here is what I found to this point:

For context I use cocoapods integration inside my Kotlin Multiplatform SDK so it works somewhat like this:

RecaptchaEnterprise Pod -> (Kotlin cocoapods plugin) -> My Kotlin SDK -> (compiled by kotlin/native) -> my iOS App

walterjgsp commented 3 months ago

What do you use to send the token from the Swift part to the Kotlin part? Do you have a small code snippet that you can share with us?

lemcoder commented 3 months ago

I use Kotlin cocoapods plugin. I do not use Swift to generate token I do all in Kotlin. The cocoapods plugin wraps the pod and generates binding code based on header files so it can be called from Kotlin. You can read about it here: https://kotlinlang.org/docs/native-cocoapods-libraries.html#from-the-cocoapods-repository I did use Swift to generate token just to check if the problem is on the backend (it is not).

mcorner commented 3 months ago

@lemcoder did you find anything?

lemcoder commented 3 months ago

@mcorner We have decided to postpone work on reCAPTCHA until we start implementing the feature that will utilize it. Until then I will try my best to provide some minimal reproducible example so you can see how the app is structured. I think it would be a good idea to provide a KMP library for reCAPTCHA Enterptise as you seem to have both targets (iOS/Android) covered already. I would gladly help with implementing that, because it would be super usefull to me