Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eicaptcha et module contactform overridé #304

Open
sirius82 opened this issue Jan 25, 2025 · 6 comments
Open

Eicaptcha et module contactform overridé #304

sirius82 opened this issue Jan 25, 2025 · 6 comments

Comments

@sirius82
Copy link

Bonjour et merci pour ce module. Cependant, j'ai une question sur le bouton concernant l'override créé par eicaptcha. Est-il nécessaire de le maintenir activé ? Avant d'installer votre module, j'avais overridé les functions getWidgetVariables et SendMessage pour ajouter des champs nom, prénom, tel 1 et tel2 au formulaire, les 3 premiers étant obligatoires. Après installation du module, les mails envoyés via le form ne contenaient plus ces champs et il m'a fallu un petit temps pour comprendre que mon override avait été écrasé par le vôtre. J'ai donc remis mon code et intégré le vôtre à la fin de la fonction SendMessage. Mais maintenant, le message est envoyé 2 fois, 1 fois avec les champs ajoutés, une fois sans. Vu que le site était spammé, je crains de désactiver cet override sans en savoir plus.
Merci d'avance.

PS 1.7.8
Eicaptcha 2.5
Thème Leo_Otis
`<?php
class ContactFormOverride extends Contactform {

public function getWidgetVariables($hookName = null, array $configuration = [])
{
    $notifications = [];

    if (Tools::isSubmit('submitMessage')) {
        $this->sendMessage();

        $notifications = [];
        if (!empty($this->context->controller->errors)) {
            $notifications['messages'] = $this->context->controller->errors;
            $notifications['nw_error'] = true;
        } elseif (!empty($this->context->controller->success)) {
            $notifications['messages'] = $this->context->controller->success;
            $notifications['nw_error'] = false;
        }
    } elseif (empty($this->context->cookie->contactFormToken)
        || empty($this->context->cookie->contactFormTokenTTL)
        || $this->context->cookie->contactFormTokenTTL < time()
    ) {
        $this->createNewToken();
    }

    if (($id_customer_thread = (int) Tools::getValue('id_customer_thread'))
        && $token = Tools::getValue('token')
    ) {
        $cm = new CustomerThread($id_customer_thread);

        if ($cm->token == $token) {
            $this->customer_thread = $this->context->controller->objectPresenter->present($cm);
        }
    }
    $this->contact['phone1'] = html_entity_decode(Tools::getvalue('phone1'));//ajout pour champ tel1
     $this->contact['phone2'] = html_entity_decode(Tools::getvalue('phone2'));//ajout pour champ tel2
     $this->contact['nom'] = html_entity_decode(Tools::getvalue('nom'));
     $this->contact['prenom'] = html_entity_decode(Tools::getvalue('prenom'));
    $this->contact['contacts'] = $this->getTemplateVarContact();
    $this->contact['message'] = Tools::getValue('message');
    $this->contact['allow_file_upload'] = (bool) Configuration::get('PS_CUSTOMER_SERVICE_FILE_UPLOAD');

    if (!(bool) Configuration::isCatalogMode()) {
        $this->contact['orders'] = $this->getTemplateVarOrders();
    } else {
        $this->contact['orders'] = [];
    }

    if (isset($this->customer_thread['email'])) {
        $this->contact['email'] = $this->customer_thread['email'];
    } else {
        $this->contact['email'] = Tools::safeOutput(
            Tools::getValue(
                'from',
                !empty($this->context->cookie->email) && Validate::isEmail($this->context->cookie->email) ?
                $this->context->cookie->email :
                ''
            )
        );
    }

    return [
        'contact' => $this->contact,
        'notifications' => $notifications,
        'token' => $this->context->cookie->contactFormToken,
        'id_module' => $this->id,
    ];
}

public function sendMessage()
{
    $extension = ['.txt', '.rtf', '.doc', '.docx', '.pdf', '.zip', '.png', '.jpeg', '.gif', '.jpg', '.webp'];
    $file_attachment = Tools::fileAttachment('fileUpload');
    $message = "Tel :  " . trim(Tools::getValue('phone1')) .  " - " . trim(Tools::getValue('phone2')) .  " - Nom : " . trim(Tools::getValue('nom')) . " - Prenom : " . trim(Tools::getValue('prenom')) . " ——— Message :  " . trim(Tools::getValue('message'));
    $phone1 = trim(Tools::getvalue('phone1'));//ajout champ tel1
    $phone2 = trim(Tools::getvalue('phone2'));//ajout cham tel2
    $nom = trim(Tools::getvalue('nom'));//ajout champ nom
    $prenom = trim(Tools::getvalue('prenom'));//ajout champ prenom
    $url = Tools::getValue('url');
    $clientToken = Tools::getValue('token');
    $serverToken = $this->context->cookie->contactFormToken;
    $clientTokenTTL = $this->context->cookie->contactFormTokenTTL;

    if (!($from = trim(Tools::getValue('from'))) || !Validate::isEmail($from)) {
        $this->context->controller->errors[] = $this->trans(
            'Invalid email address.',
            [],
            'Shop.Notifications.Error'
        );
    }
    //ajout validation téléphones
            if (!($phone1 = trim(Tools::getValue('phone1'))) || !Validate::isPhoneNumber($phone1)) {
        $this->context->controller->errors[] = $this->trans(
            'Invalid phone number.',
            [],
            'Shop.Notifications.Error'
        );
    }
            if (!Validate::isPhoneNumber($phone2)) {
        $this->context->controller->errors[] = $this->trans(
            'Invalid phone number2.',
            [],
            'Shop.Notifications.Error'
        );
    }
    // ajout validation nom
            if (!($nom = trim(Tools::getValue('nom'))) || !Validate::isName($nom)) {
        $this->context->controller->errors[] = $this->trans(
            'Invalid name.',
            [],
            'Shop.Notifications.Error'
        );
    }
    // ajout validation prénom
            if (!($prenom = trim(Tools::getValue('prenom'))) || !Validate::isName($prenom)) {
        $this->context->controller->errors[] = $this->trans(
            'Invalid first name.',
            [],
            'Shop.Notifications.Error'
        );
    }
    //fin
    if (empty($message)) {
        $this->context->controller->errors[] = $this->trans(
            'The message cannot be blank.',
            [],
            'Shop.Notifications.Error'
        );
    }
    if (!Validate::isCleanHtml($message)) {
        $this->context->controller->errors[] = $this->trans(
            'Invalid message',
            [],
            'Shop.Notifications.Error'
        );
    }
    //ajout pour tel1
    if (!Validate::isCleanHtml($phone1)) {
        $this->context->controller->errors[] = $this->trans(
            'Invalide phone 1',
            [],
            'Shop.Notifications.Error'
        );
    }
    //ajout pour tel2
    if (!Validate::isCleanHtml($phone2)) {
        $this->context->controller->errors[] = $this->trans(
            'Invalide phone 2',
            [],
            'Shop.Notifications.Error'
        );
    }


    $id_contact = (int) Tools::getValue('id_contact');
    $contact = new Contact($id_contact, $this->context->language->id);

    if (!$id_contact || !(Validate::isLoadedObject($contact))) {
        $this->context->controller->errors[] = $this->trans(
            'Please select a subject from the list provided. ',
            [],
            'Modules.Contactform.Shop'
        );
    }

    if (!empty($file_attachment['name']) && $file_attachment['error'] != 0) {
        $this->context->controller->errors[] = $this->trans(
            'An error occurred during the file-upload process.',
            [],
            'Modules.Contactform.Shop'
        );
    }
    if (!empty($file_attachment['name']) &&
              !in_array(Tools::strtolower(Tools::substr($file_attachment['name'], -4)), $extension) &&
              !in_array(Tools::strtolower(Tools::substr($file_attachment['name'], -5)), $extension)
    ) {
        $this->context->controller->errors[] = $this->trans(
            'Bad file extension',
            [],
            'Modules.Contactform.Shop'
        );
    }
    if ($url !== ''
        || empty($serverToken)
        || $clientToken !== $serverToken
        || $clientTokenTTL < time()
    ) {
        $this->context->controller->errors[] = $this->trans(
            'An error occurred while sending the message, please try again.',
            [],
            'Modules.Contactform.Shop'
        );
        $this->createNewToken();
    }

    if (!empty($this->context->controller->errors)) {
        return;
    }

    $customer = $this->context->customer;

    if (!$customer->id) {
        $customer->getByEmail($from);
    }

    /**
     * Check that the order belongs to the customer.
     */
    $id_order = (int) Tools::getValue('id_order');
    if (!empty($id_order)) {
        $order = new Order($id_order);
        $id_order = (int) $order->id_customer === (int) $customer->id ? $id_order : 0;
    }

    $id_customer_thread = CustomerThread::getIdCustomerThreadByEmailAndIdOrder($from, $id_order);

    if ($contact->customer_service) {
        if ((int) $id_customer_thread) {
            $ct = new CustomerThread($id_customer_thread);
            $ct->status = 'open';
            $ct->id_lang = (int) $this->context->language->id;
            $ct->id_contact = (int) $id_contact;
            $ct->id_order = $id_order;

            if ($id_product = (int) Tools::getValue('id_product')) {
                $ct->id_product = $id_product;
            }
            $ct->update();
        } else {
            $ct = new CustomerThread();
            if (isset($customer->id)) {
                $ct->id_customer = (int) $customer->id;
            }
            $ct->id_shop = (int) $this->context->shop->id;
            $ct->id_order = $id_order;

            if ($id_product = (int) Tools::getValue('id_product')) {
                $ct->id_product = $id_product;
            }
            $ct->id_contact = (int) $id_contact;
            $ct->id_lang = (int) $this->context->language->id;
            $ct->email = $from;
            $ct->status = 'open';
            $ct->token = Tools::passwdGen(12);
            $ct->add();
        }

        if ($ct->id) {
            $lastMessage = CustomerMessage::getLastMessageForCustomerThread($ct->id);
            $testFileUpload = (isset($file_attachment['rename']) && !empty($file_attachment['rename']));

            // if last message is the same as new message (and no file upload), do not consider this contact
            if ($lastMessage != $message || $testFileUpload) {
                $cm = new CustomerMessage();
                $cm->id_customer_thread = $ct->id;
                $cm->message = $message;

                if ($testFileUpload && rename($file_attachment['tmp_name'], _PS_UPLOAD_DIR_ . basename($file_attachment['rename']))) {
                    $cm->file_name = $file_attachment['rename'];
                    @chmod(_PS_UPLOAD_DIR_ . basename($file_attachment['rename']), 0664);
                }
                $cm->ip_address = (string) ip2long(Tools::getRemoteAddr());
                $cm->user_agent = $_SERVER['HTTP_USER_AGENT'];

                if (!$cm->add()) {
                    $this->context->controller->errors[] = $this->trans(
                        'An error occurred while sending the message.',
                        [],
                        'Modules.Contactform.Shop'
                    );
                }
            } else {
                $mailAlreadySend = true;
            }
        } else {
            $this->context->controller->errors[] = $this->trans(
                'An error occurred while sending the message.',
                [],
                'Modules.Contactform.Shop'
            );
        }
    }
    $sendConfirmationEmail = Configuration::get(self::SEND_CONFIRMATION_EMAIL);
    $sendNotificationEmail = Configuration::get(self::SEND_NOTIFICATION_EMAIL);

    if (!count($this->context->controller->errors)
        && empty($mailAlreadySend)
        && ($sendConfirmationEmail || $sendNotificationEmail)
    ) {
        $message = version_compare(_PS_VERSION_, '8.0.0', '>=') ? stripslashes($message) : Tools::stripslashes($message);
        $var_list = [
            '{firstname}' => '',
            '{lastname}' => '',
            '{order_name}' => '-',
            '{attached_file}' => '-',
            '{message}' => Tools::nl2br(Tools::htmlentitiesUTF8($message)),
            '{email}' => $from,
            '{phone1}' => Tools::nl2br(stripslashes($phone1)),//ajout tel 1
            '{phone2}' => Tools::nl2br(stripslashes($phone2)), //ajout tel2
            '{nom}' => Tools::nl2br(stripslashes($nom)), //ajout nom
            '{prenom}' => Tools::nl2br(stripslashes($prenom)), //ajout prenom
            '{product_name}' => '',
        ];

        if (isset($customer->id)) {
            $var_list['{firstname}'] = $customer->firstname;
            $var_list['{lastname}'] = $customer->lastname;
        }

        if (isset($file_attachment['name'])) {
            $var_list['{attached_file}'] = $file_attachment['name'];
        }
        $id_product = (int) Tools::getValue('id_product');

        if ($id_order) {
            $order = new Order((int) $id_order);
            $var_list['{order_name}'] = $order->getUniqReference();
            $var_list['{id_order}'] = (int) $order->id;
        }

        if ($id_product) {
            $product = new Product((int) $id_product);

            if (Validate::isLoadedObject($product) &&
                isset($product->name[Context::getContext()->language->id])
            ) {
                $var_list['{product_name}'] = $product->name[Context::getContext()->language->id];
            }
        }

        if ($sendNotificationEmail) {
            if (empty($contact->email) || !Mail::Send(
                $this->context->language->id,
                'contact',
                $this->trans('Message from contact form', [], 'Emails.Subject') . ' [no_sync]',
                $var_list,
                $contact->email,
                $contact->name,
                null,
                null,
                $file_attachment,
                null,
                _PS_MAIL_DIR_,
                false,
                null,
                null,
                $from
            )) {
                $this->context->controller->errors[] = $this->trans(
                    'An error occurred while sending the message.',
                    [],
                    'Modules.Contactform.Shop'
                );
            }
        }

        if ($sendConfirmationEmail) {
            $var_list['{message}'] = self::MESSAGE_PLACEHOLDER_FOR_OLDER_VERSION;

            if (!Mail::Send(
                $this->context->language->id,
                'contact_form',
                ((isset($ct) && Validate::isLoadedObject($ct)) ? $this->trans(
                    'Your message has been correctly sent #ct%thread_id% #tc%thread_token%',
                    [
                        '%thread_id%' => $ct->id,
                        '%thread_token%' => $ct->token,
                    ],
                    'Emails.Subject'
                ) : $this->trans('Your message has been correctly sent', [], 'Emails.Subject')),
                $var_list,
                $from,
                null,
                null,
                null,
                $file_attachment,
                null,
                _PS_MAIL_DIR_,
                false,
                null,
                null,
                $contact->email
            )) {
                $this->context->controller->errors[] = $this->trans(
                    'An error occurred while sending the message.',
                    [],
                    'Modules.Contactform.Shop'
                );
            }
        }
    }

    if (!count($this->context->controller->errors)) {
        $this->context->controller->success[] = $this->trans(
            'Your message has been successfully sent to our team.',
            [],
            'Modules.Contactform.Shop'
        );
    }
	 Hook::exec('actionContactFormSubmitBefore');
    if (!sizeof($this->context->controller->errors)) {
        parent::sendMessage();
    }
}

}`

@nenes25
Copy link
Owner

nenes25 commented Jan 25, 2025

Bonjour,

Effectivement le comportement que vous décrivez est logique au vu de l'adaptation du code qui a été faite 😄 .
Car les lignes d'override de mon module appellent la fonction parente.
Qui va donc réenvoyer l'email sans vos paramètres effectivement.

Dans votre cas je pense qu'il faudrait rajouter uniquement la ligne

Hook::exec('actionContactFormSubmitBefore');

juste avant ces lignes dans votre extrait :

if (!empty($this->context->controller->errors)) { return; }

Et ça devrait fonctionner correctement.

Cordialement,
Hervé

@sirius82
Copy link
Author

Merci beaucoup pour votre réponse. Effectivement, ça marche mieux comme ça :-). A voir si cela résout le problème des spams qui passent encore. Aucune erreur au niveau du module eicaptcha. J'ai activé les logs et comparé les dates d'envoi des spams. Pour la plupart : Captcha soumis avec succès. Pour l'un ou l'autre (mais envoyé quand même) :
2025-01-27 10:51:58: Merci de valider le captcha 2025-01-27 10:51:58: Réponse recaptcha Array ( [0] => missing-input-response )

Il y a moins de spam, mais celui-là revient plusieurs fois par jour (nom identique dans le champ ajouté)
J'avais choisi captcha v2 car il me semblait plus performant que v3. Qu'en pensez-vous ?

Merci d'avance

@nenes25
Copy link
Owner

nenes25 commented Jan 28, 2025

J'ai également une préférence à l'usage sur le V2, mais normalement ils devraient avoir la même efficacité.

Pour vérifier que la surcharge est bien fonctionnelle, si vous soumettez le formulaire sans cocher la case du captcha, est-ce que vous avez bien une erreur et l'envoi est bloqué ?
Si c'est bien le cas, le fait qu'il y'a des erreurs dans les logs montre les soumissions en erreur.
Sinon il faut peut être revoir l'implémentation de l'override.

Cordialement,
Hervé

@sirius82
Copy link
Author

Bonjour Hervé,
Oui, j'avais vérifié, la surcharge est bien fonctionnelle, le message ne part pas si la case n'est pas cochée. Manifestement ce RobertNob ne doit pas être considéré comme spammeur par Google. Vu que tous les spams de ces derniers jours avait ce nom dans le champ nom que j'avais rajouté, j'ai ajouté un return si c'est ce nom là, donc le Robert revient sur le formulaire :-). Depuis hier, plus de messages ... jusqu'à ce qu'il trouve la parade. Car jusqu'ici il mettait chaque fois une adresse mail différente, et le contenu pouvait être en anglais, en thaï, en suédois, etc ... D'ailleurs, question, à quoi cela sert de mettre la langue dans la config du captcha ? Vu qu'il remplit tous les champs, je vais essayer d'ajouter un honeypot, ce sera une barrière suppplémentaire. Vous avez bien un tuto là-dessus ?
Merci pour votre travail !
Cordialement
Camille

@nenes25
Copy link
Owner

nenes25 commented Jan 28, 2025

Concernant la langue du captcha, par défaut c'est la même que celle du navigateur.
Ce paramètre permets de la forcer.
Non je n'ai malheureusement pas de tuto sur les honeypot, mais je pense que ça doit facilement se trouver :)
Quand je vois qu'il existe des extensions telles-que celles-ci : https://chromewebstore.google.com/detail/recaptcha-solver-auto-cap/infdcenbdoibcacogknkjleclhnjdmfh?pli=1 je ne suis pas sur que la solution reste 100% infranchissable 😢

@sirius82
Copy link
Author

Ben mince ! Google crée le captcha puis autorise ce genre d'extension ... on est mal barré ! En tout cas, mon petit malin a dû trouver la raison de son blocage, un spam reçu aujourd'hui avec un autre nom ... Mais les n° de tel qu'il entre dans mes champs ajoutés commencent tous par 8 ... Je vais chercher une manière de bloquer si le tel ne commence pas par 0. Et le honeypot. Je me disais que si, au lieu de bloquer le spammeur sur son nom, j'aurais pu envoyer son mail sur une fausse adresse mail plutôt que sur le site, il ne se serait pas rendu compte et n'aurait pas cherché à contourner le blocage ...

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

No branches or pull requests

2 participants