Skip to content

Update code to use the v2 api from Friendy-Captcha#10

Open
KRMM2025 wants to merge 2 commits into
ossycodes:masterfrom
KRMM2025:update-to-v2-api
Open

Update code to use the v2 api from Friendy-Captcha#10
KRMM2025 wants to merge 2 commits into
ossycodes:masterfrom
KRMM2025:update-to-v2-api

Conversation

@KRMM2025
Copy link
Copy Markdown

I have updated this repository to support FriendlyCaptcha API Version 2.

This is a breaking change, i recommend this as a part of a major update.

As part of this update:

  • I removed the use of unpkg, because the FriendlyCaptcha SDK (@friendlycaptcha/sdk@0.1.36) is only available via jsdelivr.net.

  • I updated the tests accordingly to use the FriendlyCaptcha SDK.

  • I removed the option to select a puzzle, as the current @friendlycaptcha/sdk package does not support that functionality.

  • I updated the API requests to use the correct URL and request structure required by FriendlyCaptcha API V2.

  • I also adjusted the error messages in validation.php to align with the new API response format.

@wi-wissen
Copy link
Copy Markdown
Contributor

@KRMM2025 Would that mean that the package would then become incompatible with https://github.com/FriendlyCaptcha/friendly-lite-server ?

@KRMM2025
Copy link
Copy Markdown
Author

@KRMM2025 Would that mean that the package would then become incompatible with https://github.com/FriendlyCaptcha/friendly-lite-server ?

@wi-wissen I'm not familiar with the "friendly-lite-server" repository and can't say for sure that the v2 puzzle can be solved by the lite server. However, you could make this pull request a major release so that people with the v1 lite server can simply continue using an older version of this package.

@ossycodes
Copy link
Copy Markdown
Owner

@wi-wissen what do you think ?

@wi-wissen
Copy link
Copy Markdown
Contributor

@ossycodes Thank you for the follow-up. I have only been a minor contributor to https://github.com/FriendlyCaptcha/friendly-lite-server and here. 😊
Yes, the open-source Lite server backend would no longer be compatible with this change:

https://github.com/FriendlyCaptcha/friendly-lite-server/blob/e93be67590aa2f5216459047e5c14d14ac5ee90b/public/siteverify.php#L27

I fully understand that @KRMM2025 wants to use the new API though. Perhaps we could address this cleanly by introducing two major versions on Packagist — keeping the current v1.x for those using the self-hosted Lite server like me, and releasing a v2.x that targets the new cloud API. That way both use cases are supported without breaking existing installations.

@ossycodes
Copy link
Copy Markdown
Owner

ossycodes commented Mar 22, 2026

@KRMM2025 did you properly test this please ?

Overall review body (REQUEST_CHANGES):

Thanks for this contribution — the direction is correct, and the v2 API changes look well thought out. However, two critical bugs would break the package at runtime, plus a few smaller
issues.

  • Critical :
  1. FriendlyCaptchaServiceProvider::register() is not updated. The new constructor is __construct($secret, $sitekey, $verify, $options = []), but register() still passes 5 args — puzzle_endpoint will be
    bound to $verify and verify_endpoint to $options, so every verification call silently hits the wrong URL.
  2. src/config/friendlycaptcha.php not updated — still has puzzle_endpoint (v1 URL) and verify_endpoint still defaults to the v1 siteverify URL. Remove puzzle_endpoint and update the default to
    https://global.frcapi.com/api/v2/captcha/siteverify.

Inline comments:

  • lang/en/validation.php line 11: Typo — Authentification should be Authentication. Applies to auth_required and auth_invalid.
  • lang/de/validation.php line 11: Same typo.
  • src/Rules/FriendlyCaptcha.php (default case): bad_request is still in the lang files, but no longer has a case in the switch — it falls through to unexpected. Either add case "bad_request" back or
    Remove the key from both lang files.
  • src/FriendlyCaptcha.php (constructor): Removing $puzzle and moving auth to X-API-Key header is correct. Just make sure ServiceProvider::register() is updated to match.
  • src/FriendlyCaptchaServiceProvider.php (Blade directive): Correctly simplified. Worth noting in a changelog that @friendlyCaptchaRenderWidgetScripts('jsdelivr') is a breaking change for existing
    users.

@KRMM2025
Copy link
Copy Markdown
Author

Thanks for your reply. I will look on it and make some fixes in the next days. 👍

@sdebacker
Copy link
Copy Markdown

Hi, is there some news about this PR? Thank you.

Copy link
Copy Markdown
Owner

@ossycodes ossycodes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this contribution — migrating to the v2 API is the right direction and the overall structure is solid. However a thorough review found 2 crash-on-use bugs and 6 additional issues that need to be fixed before this can be merged.


🔴 Critical — crashes at runtime

1. Fatal TypeError when captcha field is empty — src/Rules/FriendlyCaptcha.php:24

verifyResponse() returns false (a bool) when $solution is empty. passes() then calls $response->isSuccess() on that false:

$response = $this->friendlyCaptchaClient->verifyResponse($value); // can return false
if ($response->isSuccess()) { // fatal: "Call to a member function isSuccess() on bool"

Any form submission where the captcha field is missing (the most common spam scenario) causes a 500 error instead of a validation failure.

Fix: Change verifyResponse() to always return $this — set $this->isSuccess = false instead of return false. Or guard the call in passes():

if (!$response || !$response->isSuccess()) { ... }

2. bootLang() silently overwrites bootMacro()src/FriendlyCaptchaServiceProvider.php

boot() calls bootMacro() then bootLang(). Both call Rule::macro('friendlycaptcha', ...). Laravel's Macroable::macro is a plain array write — the second registration silently wins. The surviving closure calls $this->loadTranslationsFrom(...) where $this is the Rule class, which has no such method → fatal "Call to undefined method". Rule::friendlycaptcha() never returns a rule object, breaking all captcha validation.

Fix: Remove the Rule::macro call from bootLang(). Load translations directly in boot():

public function boot()
{
    // ...
    $this->loadTranslationsFrom(__DIR__.'/../lang', 'friendlycaptcha');
    $this->bootMacro();
    // ...
}

🟠 High

3. $this->errors vs declared $this->errorsrc/FriendlyCaptcha.php

The class declares protected $error = [] (singular) but all reads/writes use $this->errors (plural). Dynamic undeclared property — deprecated in PHP 8.2, fatal in PHP 9. More critically: on the success path $this->errors is never assigned, so getErrors() returns null. The foreach ($response->getErrors() as ...) in Rules/FriendlyCaptcha.php then throws "foreach argument must be of type array|object, null given" on every successful captcha verification.

Fix: Rename the declared property to protected $errors = [].

4. Illuminate\Contracts\Validation\Rule removed in Laravel 12 — src/Rules/FriendlyCaptcha.php

use Illuminate\Contracts\Validation\Rule;
class FriendlyCaptcha implements Rule

This interface was removed in Laravel 12. The package's composer.json supports illuminate/support ^12.0|^13.0, so on Laravel 12+ this class fails to load with "Interface not found", making the validation rule completely unusable.

Fix: Implement Illuminate\Contracts\Validation\ValidationRule instead, replacing passes() + message() with:

public function validate(string $attribute, mixed $value, \Closure $fail): void
{
    $response = $this->friendlyCaptchaClient->verifyResponse($value);
    if (!$response->isSuccess()) {
        foreach ($response->getErrors() as $code) {
            $fail($this->mapErrorCodeToMessage($code));
        }
    }
}

5. form_params sends form-encoded but v2 endpoint expects JSON — src/FriendlyCaptcha.php

The config now defaults to https://global.frcapi.com/api/v2/captcha/siteverify. Guzzle's form_params sends Content-Type: application/x-www-form-urlencoded. The FriendlyCaptcha v2 API is a JSON REST API, so this will cause every verification to fail.

Fix: Replace form_params with json:

$response = $this->http->request('POST', $this->verify, [
    'headers' => $headers,
    'json'    => $data,
]);

🟡 Medium

6. Tests use @test annotation — tests/FriendlyCaptchaTest.php

PHPUnit 11 (pulled in by testbench 9+ for Laravel 11+) removed the @test docblock annotation. Both test methods are invisible to PHPUnit — the suite exits with "no tests found" (exit code 2), breaking CI.

Fix: Rename methods to use the test_ prefix and drop the annotations:

public function test_it_can_render_jsdelivr_widget_script_correctly()
public function test_it_can_render_widget_correctly()

7. SDK version inconsistency — CHANGELOG.md vs source files

src/FriendlyCaptcha.php and src/FriendlyCaptchaServiceProvider.php both hardcode @friendlycaptcha/sdk@0.1.36, but CHANGELOG.md documents @0.2.0. Please align these — use @0.2.0 consistently across all files.

8. Translations never loaded

Even after fixing issue #2, the lang files won't be registered unless loadTranslationsFrom is called directly in boot() (not inside a macro closure). The fix for #2 above handles this correctly.


Once these are addressed this will be ready to merge as a major release (v4.0.0). Happy to review a follow-up — thanks again for the contribution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants