diff --git a/.env.example b/.env.example index 5fecbcf..a886ae9 100644 --- a/.env.example +++ b/.env.example @@ -36,6 +36,11 @@ MAIL_LIST_CONTACTFORM= ANALYTICS_GOOGLE_ID= +# Google Recaptcha +GOOGLE_RECAPTCHA_PUBLIC= +GOOGLE_RECAPTCHA_PRIVATE= +GOOGLE_RECAPTCHA_VERSION= + LDC_WEB_API_KEY="MY_KEY" LDC_STATUS_CHECKER_API_KEY="MY_KEY" -LDC_STATUS_CHECKER_UUID="UUID_PROJECT" \ No newline at end of file +LDC_STATUS_CHECKER_UUID="UUID_PROJECT" diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 8b05f8c..ce1176d 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -6,19 +6,10 @@ use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Routing\Controller as BaseController; -use App\Enums\Country; class Controller extends BaseController { use AuthorizesRequests; use DispatchesJobs; use ValidatesRequests; - - /** - * Perform any actions required when creating the object. - */ - public function __construct() - { - view()->share('availableCountries', Country::toArray()); - } } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 2299fc3..baed7a9 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -39,6 +39,7 @@ class Kernel extends HttpKernel 'lang-check', \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, + \App\Http\Middleware\SecureHeaders::class ], 'api' => [ diff --git a/app/Http/Middleware/SecureHeaders.php b/app/Http/Middleware/SecureHeaders.php new file mode 100644 index 0000000..ae4cab3 --- /dev/null +++ b/app/Http/Middleware/SecureHeaders.php @@ -0,0 +1,88 @@ +removeUnwantedHeaders($this->unwantedHeaderList); + $response = $next($request); + $response->headers->set('Referrer-Policy', 'no-referrer-when-downgrade'); + $response->headers->set('X-Content-Type-Options', 'nosniff'); + $response->headers->set('X-XSS-Protection', '1; mode=block'); + $response->headers->set('X-Frame-Options', 'SAMEORIGIN'); + $response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains;'); + $cspPolicies = [ + // "default-src 'none';", + "manifest-src 'self';", + "connect-src 'self' https://*.googletagmanager.com blob:;", + "img-src * https://*.googletagmanager.com data: blob:;", + 'frame-src ' . implode(' ', [ + 'https://www.google.com/recaptcha/', + 'https://recaptcha.google.com/recaptcha/', + ]), + // "font-src 'self' data:;", + // ! Using CKEditor will must have unsafe-inline style + // phpcs:ignore Generic.Files.LineLength.TooLong + "style-src 'self' 'unsafe-inline';", + // ! If you dont use ckeditor use this + // "style-src 'self' 'nonce-$nonce';", + // phpcs:ignore Generic.Files.LineLength.TooLong + 'script-src ' . implode(" ", [ + '\'self\'', + 'https://www.google.com/recaptcha/', + 'https://www.gstatic.com/recaptcha/', + 'https://*.googletagmanager.com', + ]) . ' ' . $jsDev . ';' + ]; + $response->headers->set( + 'Content-Security-Policy', + implode(' ', $cspPolicies) . $reportUri + ); + $response->headers->set('Feature-Policy', 'fullscreen \'self\';'); + return $response; + } + + /** + * Remove unwanted headers + * + * @param array $headerList + * @return void + */ + private function removeUnwantedHeaders(array $headerList) + { + foreach ($headerList as $header) { + header_remove($header); + } + } +} diff --git a/app/Http/Requests/ContactFormRequest.php b/app/Http/Requests/ContactFormRequest.php index cb5ed3d..affa6c5 100644 --- a/app/Http/Requests/ContactFormRequest.php +++ b/app/Http/Requests/ContactFormRequest.php @@ -2,6 +2,7 @@ namespace App\Http\Requests; +use App\Lib\Helpers\ToolboxHelper; use Illuminate\Foundation\Http\FormRequest; class ContactFormRequest extends FormRequest @@ -23,6 +24,8 @@ class ContactFormRequest extends FormRequest */ public function rules() { + ToolboxHelper::validateRecaptcha($this, \config('services.google.recaptcha.version')); + return [ 'civilite' => 'required|in:monsieur,madame', 'name' => 'required|string|min:2', diff --git a/app/Lib/Helpers/ToolboxHelper.php b/app/Lib/Helpers/ToolboxHelper.php new file mode 100644 index 0000000..7cce240 --- /dev/null +++ b/app/Lib/Helpers/ToolboxHelper.php @@ -0,0 +1,65 @@ +all(), [ + 'g-recaptcha-response' => [ + 'required', 'string', + // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed, Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed + function ($attribute, $value, $fail) use ($isV3) { + try { + $response = Http::asForm()->post('https://www.google.com/recaptcha/api/siteverify', [ + 'secret' => config('services.google.recaptcha.private'), + 'response' => \strval($value), + 'remoteip' => app('clientIp') + ]); + if ($e = $response->toException()) { + throw $e; + } + if ($isV3) { + if ( + !$response->json('success') or + !$response->json('challenge_ts') or + Carbon::parse($response->json('challenge_ts'))->lessThan(\now('utc')->subMinutes(5)) or + $response->json('hostname') !== \parse_url(config('app.url'), \PHP_URL_HOST) or + !$response->json('score') + ) { + throw new \RuntimeException(); + } + if (\floatval($response->json('score')) < 0.8) { + $fail("Vous n'avez pas obtenu un score assez élevé lors de la validation du recaptcha"); + } + return; + } + if ( + !$response->json('success') or + !$response->json('challenge_ts') or + Carbon::parse($response->json('challenge_ts'))->lessThan(\now('utc')->subMinutes(5)) or + $response->json('hostname') !== \parse_url(config('app.url'), \PHP_URL_HOST) + ) { + throw new \RuntimeException(); + } + } catch (\Exception $e) { + $fail('Erreur lors de la validation du formulaire veuillez réssayer'); + } //end try + } + ] + ], [], ['g-recaptcha-response' => 'reCaptcha']); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 08d3a8b..ab6e358 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -4,6 +4,8 @@ namespace App\Providers; use Illuminate\Support\Facades\URL; use Illuminate\Support\ServiceProvider; +use App\Enums\Country; +use Illuminate\Support\Facades\Cache; class AppServiceProvider extends ServiceProvider { @@ -24,5 +26,18 @@ class AppServiceProvider extends ServiceProvider public function boot() { URL::forceScheme('https'); + + // * HA PROXY FIX + app()->singleton('clientIp', function () { + if (config('app.env') === 'local') { + return request()->getClientIp(); + } + return request()->server('HTTP_X_FORWARDED_FOR') ?? request()->getClientIp(); + }); + + $listCountries = Cache::remember('listCountries', 60, function () { + return Country::toArray(); + }); + view()->share('availableCountries', $listCountries ?? Country::toArray()); } } diff --git a/config/services.php b/config/services.php index 915dfe7..013f0ae 100644 --- a/config/services.php +++ b/config/services.php @@ -30,4 +30,12 @@ return [ 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), ], + 'google' => [ + 'recaptcha' => [ + 'public' => env('GOOGLE_RECAPTCHA_PUBLIC'), + 'private' => env('GOOGLE_RECAPTCHA_PRIVATE'), + 'version' => env('GOOGLE_RECAPTCHA_VERSION', "3") === "3" ? true : false + ] + ], + ]; diff --git a/package-lock.json b/package-lock.json index 9ef8377..ab460b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16770,4 +16770,4 @@ "dev": true } } -} +} \ No newline at end of file diff --git a/resources/js/frontend/custom.js b/resources/js/frontend/custom.js index a955afa..f102586 100644 --- a/resources/js/frontend/custom.js +++ b/resources/js/frontend/custom.js @@ -30,6 +30,33 @@ docReady(function () { } }; + // PAGE CONTACT + let eltCountry = document.getElementById("country"); + if (eltCountry) { + eltCountry.addEventListener("click", function () { + showDromField(this); + }); + } + + let eltsConsoRecla = document.getElementsByClassName("consoRecla"); + if (eltsConsoRecla) { + for (let ii = 0; ii < eltsConsoRecla.length; ii++) { + eltsConsoRecla[ii].addEventListener("click", function () { + showReclaFields(); + }); + } + } + + let eltsOtherRecla = document.getElementsByClassName("otherRecla"); + if (eltsOtherRecla) { + for (let ii = 0; ii < eltsOtherRecla.length; ii++) { + eltsOtherRecla[ii].addEventListener("click", function () { + hideReclaFields(); + }); + } + } + // FIN PAGE CONTACT + document .getElementById("backtotop") .addEventListener("click", function () { diff --git a/resources/views/front/contact.blade.php b/resources/views/front/contact.blade.php index 1ba8615..3cb2217 100644 --- a/resources/views/front/contact.blade.php +++ b/resources/views/front/contact.blade.php @@ -48,14 +48,14 @@

{!! __('Une question ? Une idée ? Un conseil ?
Des informations sur nos produits ?') !!}

-

{!! __('N’hésitez-pas à nous contacter en renseignant le formulaire ci-dessous.
Nous traiterons votre demande avec la plus grande attention dans les meilleurs délais.') !!}

+

{!! __('N\'hésitez-pas à nous contacter en renseignant le formulaire ci-dessous.
Nous traiterons votre demande avec la plus grande attention dans les meilleurs délais.') !!}

@if(session()->has('status'))
{{ __('Votre message a bien été envoyé !') }}
{{ __('Nos services mettent tout en oeuvre pour y répondre au plus vite.') }}
@endif -
+ @csrf @if ($errors->any()) @foreach ($errors->all() as $error) @@ -110,10 +110,10 @@
- @foreach($availableCountries as $country) - + @endforeach
@@ -141,16 +141,16 @@ {{ __('Préciser votre demande') }} :
@@ -198,6 +198,7 @@
+
@@ -207,53 +208,67 @@ @endsection @push('scripts') - + + + @endpush diff --git a/resources/views/layouts/frontend.blade.php b/resources/views/layouts/frontend.blade.php index b663372..e7840bb 100644 --- a/resources/views/layouts/frontend.blade.php +++ b/resources/views/layouts/frontend.blade.php @@ -17,9 +17,9 @@
- + @stack('scripts') - \ No newline at end of file + diff --git a/resources/views/layouts/frontend/app-header.blade.php b/resources/views/layouts/frontend/app-header.blade.php index 59584b7..d5a00fe 100644 --- a/resources/views/layouts/frontend/app-header.blade.php +++ b/resources/views/layouts/frontend/app-header.blade.php @@ -124,11 +124,11 @@ @push('scripts') - -@endpush \ No newline at end of file +@endpush diff --git a/resources/views/layouts/frontend/cookie.blade.php b/resources/views/layouts/frontend/cookie.blade.php index 031f96d..d0d9779 100644 --- a/resources/views/layouts/frontend/cookie.blade.php +++ b/resources/views/layouts/frontend/cookie.blade.php @@ -86,7 +86,7 @@ @push('scripts') - @endpush