Skip to content

fix: validation du payeur insensible à la casse et remontée des erreurs API - #19

Open
lpmcsn wants to merge 1 commit into
HelloAsso:fix/RUN-3788-token-race-condition-and-special-charsfrom
lpmcsn:fix/complement-pr16
Open

fix: validation du payeur insensible à la casse et remontée des erreurs API#19
lpmcsn wants to merge 1 commit into
HelloAsso:fix/RUN-3788-token-race-condition-and-special-charsfrom
lpmcsn:fix/complement-pr16

Conversation

@lpmcsn

@lpmcsn lpmcsn commented Aug 19, 2026

Copy link
Copy Markdown

Pour compléter #16, sur la branche de laquelle elle est basée. Elle corrige trois points que la #16 ne couvre pas, et ajuste la classe de caractères de sa correction de regex.

Sur mon instance, une commande passée avec le prénom TEST a franchi validate_fields() et déclenché un 400 ArgumentInvalid côté API HelloAsso, alors que la liste de noms interdits contient déjà 'test'.

1. validate_fields() : liste de noms interdits sensible à la casse

in_array('TEST', array(..., 'test'))  // false
in_array('Test', array(..., 'test'))  // false

TEST, Test, ADMIN franchissent la validation qu'ils sont censés déclencher. Corrigé par mb_strtolower(trim(...)), avec la liste extraite en variable pour éviter sa duplication entre prénom et nom.

2. validate_fields() : classe de caractères de la regex

La #16 corrige à juste titre ! en [^, mais le jeu de caractères conservé ne contient ni î, ni ï, ni ô, ni les majuscules accentuées, et le motif n'a pas le flag /u. Donc la classe est évaluée octet par octet sur de l'UTF-8. Une fois la négation active, cela refuse au checkout des prénoms français courants.

Constaté en déployant la #16 seule sur mon instance : Benoît est refusé avec « Le prénom ne doit pas contenir de caractères spéciaux ni de caractères n'appartenant pas à l'alphabet latin ».

Élargi en /[^a-zA-ZÀ-ÿ\' -]/u, ce qui laisse passer les prénoms accentués et composés tout en continuant de rejeter les caractères spéciaux et les alphabets non latins.

3. validate_fields() : comparaison prénom/nom

$firstName === $lastName ne détecte pas Martin / martin. Comparaison alignée sur le reste, insensible à la casse et aux espaces de bord.

4. process_payment() : remontée du message de l'API

Dans le bloc !isset($response_data->redirectUrl), le corps de la réponse contient déjà un message exploitable (Le champ prénom est invalide). Le remonter évite de laisser le donateur devant un message générique sans piste de correction.

5. HELLOASSO_REFRESH_TOKEN_LIFETIME définie trois fois

La constante est définie à l'identique dans cron/helloasso-woocommerce-cron.php l.4, helloasso-api/helloasso-woocommerce-api.php l.7 et wc-api/helloasso-woocommerce-wc-api.php l.7, tous chargés dans la même requête, d'où un PHP Warning: Constant ... already defined à chaque chargement. Ajout d'un garde defined().

Fixes # (issue)

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Testé sur une instance de production : WordPress 7.0.4, WooCommerce 11.0.1, PHP 8.3.6, plugin 1.1.2, tunnel de commande classique, mode production (test_mode: no).

Trois états successifs ont été déployés et comparés, chacun suivi d'un systemctl reload php8.3-fpm et de commandes réelles.

État A — plugin 1.1.2 tel quel

  • TEST franchit la validation, checkout-intents répond 400 ArgumentInvalid, process_payment() retourne {"result":"success","redirect":null,"order_id":6057} (capturé sur le filtre woocommerce_payment_successful_result). Le checkout échoue sur la redirection nulle.
  • PHP Warning: Undefined property: stdClass::$redirectUrl ... on line 871 dans debug.log.

État B — branche de la #16 seule

État C — cette branche

Saisie Attendu Obtenu
Benoît / Parme passe page de paiement HelloAsso, checkout-intents en 200
TEST / PARME bloqué au checkout « Le prénom ne peut pas être TEST », aucun appel API dans les logs
Pierre / Parme passe page de paiement HelloAsso, checkout-intents en 200
Ivan# / Petrov bloqué au checkout message caractères spéciaux

debug.log ne contient plus aucun Undefined property: stdClass::$redirectUrl ni Constant ... already defined après le déploiement de l'état C.

Checklist:

  • My code follows the code style of this project.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have made corresponding changes to the documentation.
  • My changes generate no new warnings.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • Any dependent changes have been merged and published in downstream modules.

Sur les deux cases relatives aux tests : le dépôt ne comporte pas d'infrastructure de test (pas de PHPUnit, pas de CI, composer.json sans require-dev), il n'y avait donc pas de hook où brancher un test automatisé. La vérification a été faite manuellement sur une instance réelle, selon le protocole ci-dessus. Si besoin, nous pouvons voir pour créer les tests associés.

Sur la documentation : aucun changement de comportement documenté publiquement, hormis l'élargissement de la classe de caractères acceptés dans les champs prénom et nom.

…rs API

Complète la PR HelloAsso#16, sur laquelle cette branche est basée.

- validate_fields() : la liste de noms interdits était comparée avec
  in_array() sensible à la casse, laissant passer TEST, Test, ADMIN.
  Comparaison via mb_strtolower(trim(...)) et liste extraite en variable.

- validate_fields() : élargit la classe de caractères autorisés à
  /[^a-zA-ZÀ-ÿ\' -]/u. La liste de la PR HelloAsso#16 ne contient ni î, ï, ô, ni
  les majuscules accentuées, et sans le flag /u la classe est évaluée
  octet par octet sur de l'UTF-8 : Émile, Benoît, Loïc, Anaïs, Jérôme et
  Éric étaient refusés au checkout.

- validate_fields() : comparaison prénom/nom insensible à la casse et
  aux espaces de bord.

- process_payment() : remonte le message d'erreur renvoyé par l'API
  plutôt qu'un message générique, le corps de la réponse contenant déjà
  une indication exploitable par le donateur.

- HELLOASSO_REFRESH_TOKEN_LIFETIME est définie à l'identique dans trois
  fichiers chargés dans la même requête, d'où un warning PHP à chaque
  chargement. Ajout d'un garde defined().
@lpmcsn lpmcsn changed the title Complète #16 cf. commentaire détaillé sur cette PR fix: validation du payeur insensible à la casse et remontée des erreurs API Aug 19, 2026
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.

1 participant