fix: 🐛 add leaflet package and resolve csp errors

This commit is contained in:
Alexis Gousseau 2025-04-15 12:45:27 +02:00
parent aa66e8977e
commit 2284d3ca0f
8 changed files with 164 additions and 52 deletions

2
.gitignore vendored
View file

@ -6,6 +6,8 @@
/public/uploads /public/uploads
/public/cache /public/cache
/public/sitemap.xml /public/sitemap.xml
/public/marker-icon.png
/public/marker-shadow.png
/storage/*.key /storage/*.key
/vendor /vendor
.env .env

View file

@ -7,7 +7,6 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\View; use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Vite; use Illuminate\Support\Facades\Vite;
use Symfony\Component\HttpFoundation\Response;
class SecureHeaders class SecureHeaders
{ {
@ -31,7 +30,7 @@ class SecureHeaders
* @return \Symfony\Component\HttpFoundation\Response * @return \Symfony\Component\HttpFoundation\Response
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint * @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
*/ */
public function handle(Request $request, Closure $next): Response public function handle(Request $request, Closure $next): \Symfony\Component\HttpFoundation\Response
{ {
// phpcs:enable // phpcs:enable
View::share('nonce', $nonce = Vite::useCspNonce()); View::share('nonce', $nonce = Vite::useCspNonce());
@ -55,7 +54,9 @@ class SecureHeaders
'https://yl.s-web.fr', 'https://yl.s-web.fr',
'https://api-adresse.data.gouv.fr' 'https://api-adresse.data.gouv.fr'
]) . ';', ]) . ';',
"img-src 'self' data: blob:;", "img-src 'self' data: blob: " . implode(' ', [
'https://tile.openstreetmap.org/'
]) . ';',
// ! Blob required for printjs // ! Blob required for printjs
'frame-src ' . implode(' ', [ 'frame-src ' . implode(' ', [
'https://www.google.com/recaptcha/', 'https://www.google.com/recaptcha/',
@ -74,7 +75,6 @@ class SecureHeaders
'https://cdn.jsdelivr.net', 'https://cdn.jsdelivr.net',
'https://use.fontawesome.com', 'https://use.fontawesome.com',
'https://fonts.googleapis.com', 'https://fonts.googleapis.com',
' https://unpkg.com/leaflet@1.9.3/dist/leaflet.css'
]) . ';', ]) . ';',
// ! If you dont use ckeditor use this // ! If you dont use ckeditor use this
// "style-src 'self' 'nonce-$nonce';", // "style-src 'self' 'nonce-$nonce';",
@ -84,7 +84,6 @@ class SecureHeaders
'https://unpkg.com', 'https://unpkg.com',
'https://www.googletagmanager.com', 'https://www.googletagmanager.com',
'https://cdnjs.cloudflare.com', 'https://cdnjs.cloudflare.com',
'https://unpkg.com/leaflet@1.9.3/dist/leaflet.js',
"$scheme://www.google-analytics.com", "$scheme://www.google-analytics.com",
]) . ';' ]) . ';'
]; ];

125
package-lock.json generated
View file

@ -1,5 +1,5 @@
{ {
"name": "srcs", "name": "lionor",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
@ -34,6 +34,7 @@
"postcss-discard-comments": "^5.1.2", "postcss-discard-comments": "^5.1.2",
"prettier": "latest", "prettier": "latest",
"resolve-url-loader": "^5.0.0", "resolve-url-loader": "^5.0.0",
"rollup-plugin-copy": "^3.5.0",
"sass": "latest", "sass": "latest",
"slugify": "^1.6.6", "slugify": "^1.6.6",
"stylelint-config-idiomatic-order": "github:ream88/stylelint-config-idiomatic-order", "stylelint-config-idiomatic-order": "github:ream88/stylelint-config-idiomatic-order",
@ -2550,12 +2551,31 @@
"integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==", "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==",
"dev": true "dev": true
}, },
"node_modules/@types/fs-extra": {
"version": "8.1.5",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz",
"integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/geojson": { "node_modules/@types/geojson": {
"version": "7946.0.11", "version": "7946.0.11",
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.11.tgz", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.11.tgz",
"integrity": "sha512-L7A0AINMXQpVwxHJ4jxD6/XjZ4NDufaRlUJHjNIFKYUFBH1SvOW+neaqb0VTRSLW5suSrSu19ObFEFnfNcr+qg==", "integrity": "sha512-L7A0AINMXQpVwxHJ4jxD6/XjZ4NDufaRlUJHjNIFKYUFBH1SvOW+neaqb0VTRSLW5suSrSu19ObFEFnfNcr+qg==",
"dev": true "dev": true
}, },
"node_modules/@types/glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
"integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==",
"dev": true,
"dependencies": {
"@types/minimatch": "*",
"@types/node": "*"
}
},
"node_modules/@types/json-schema": { "node_modules/@types/json-schema": {
"version": "7.0.13", "version": "7.0.13",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz",
@ -2571,6 +2591,12 @@
"@types/geojson": "*" "@types/geojson": "*"
} }
}, },
"node_modules/@types/minimatch": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
"integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==",
"dev": true
},
"node_modules/@types/minimist": { "node_modules/@types/minimist": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.3.tgz", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.3.tgz",
@ -2578,6 +2604,15 @@
"dev": true, "dev": true,
"peer": true "peer": true
}, },
"node_modules/@types/node": {
"version": "22.14.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz",
"integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==",
"dev": true,
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/@types/normalize-package-data": { "node_modules/@types/normalize-package-data": {
"version": "2.4.2", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.2.tgz", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.2.tgz",
@ -3583,6 +3618,12 @@
"dev": true, "dev": true,
"peer": true "peer": true
}, },
"node_modules/colorette": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
"integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==",
"dev": true
},
"node_modules/combined-stream": { "node_modules/combined-stream": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -6063,6 +6104,82 @@
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
"node_modules/rollup-plugin-copy": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.5.0.tgz",
"integrity": "sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==",
"dev": true,
"dependencies": {
"@types/fs-extra": "^8.0.1",
"colorette": "^1.1.0",
"fs-extra": "^8.1.0",
"globby": "10.0.1",
"is-plain-object": "^3.0.0"
},
"engines": {
"node": ">=8.3"
}
},
"node_modules/rollup-plugin-copy/node_modules/fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"dev": true,
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
},
"engines": {
"node": ">=6 <7 || >=8"
}
},
"node_modules/rollup-plugin-copy/node_modules/globby": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz",
"integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==",
"dev": true,
"dependencies": {
"@types/glob": "^7.1.1",
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
"fast-glob": "^3.0.3",
"glob": "^7.1.3",
"ignore": "^5.1.1",
"merge2": "^1.2.3",
"slash": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/rollup-plugin-copy/node_modules/is-plain-object": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz",
"integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/rollup-plugin-copy/node_modules/jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
"dev": true,
"optionalDependencies": {
"graceful-fs": "^4.1.6"
}
},
"node_modules/rollup-plugin-copy/node_modules/universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"dev": true,
"engines": {
"node": ">= 4.0.0"
}
},
"node_modules/run-parallel": { "node_modules/run-parallel": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@ -6996,6 +7113,12 @@
"node": ">=14.17" "node": ">=14.17"
} }
}, },
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true
},
"node_modules/unicode-canonical-property-names-ecmascript": { "node_modules/unicode-canonical-property-names-ecmascript": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",

View file

@ -41,6 +41,7 @@
"postcss-discard-comments": "^5.1.2", "postcss-discard-comments": "^5.1.2",
"prettier": "latest", "prettier": "latest",
"resolve-url-loader": "^5.0.0", "resolve-url-loader": "^5.0.0",
"rollup-plugin-copy": "^3.5.0",
"sass": "latest", "sass": "latest",
"slugify": "^1.6.6", "slugify": "^1.6.6",
"stylelint-config-idiomatic-order": "github:ream88/stylelint-config-idiomatic-order", "stylelint-config-idiomatic-order": "github:ream88/stylelint-config-idiomatic-order",

View file

@ -6,6 +6,7 @@
// * VENDOR // * VENDOR
@import "./vendor/ckEditorContent"; @import "./vendor/ckEditorContent";
@import "./vendor/bootstrap"; @import "./vendor/bootstrap";
@import "leaflet";
// * UTILITIES // * UTILITIES
@import "./utilities/bootstrap-custom"; @import "./utilities/bootstrap-custom";

View file

@ -10,7 +10,7 @@ import parseLaravelErrorMessages from "./../../modules/parseLaravelErrorMessages
import route from "./../../modules/route"; import route from "./../../modules/route";
import toast from "./../../modules/toast"; import toast from "./../../modules/toast";
import trans from "./../../modules/trans"; import trans from "./../../modules/trans";
import * as L from "leaflet"; import L from "leaflet";
import { defineComponent } from "vue"; import { defineComponent } from "vue";
@ -237,18 +237,10 @@ export default defineComponent({
map.eachLayer(function (layer: L.Layer) { map.eachLayer(function (layer: L.Layer) {
map.removeLayer(layer); map.removeLayer(layer);
}); });
L.tileLayer( L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
"https://{s}.tile.jawg.io/jawg-sunny/{z}/{x}/{y}{r}.png?access-token={accessToken}", maxZoom: 16,
{ attribution: "&copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a>"
attribution: }).addTo(this.map);
"<a href='http://jawg.io' title='Tiles Courtesy of Jawg Maps' target='_blank'>&copy; <b>Jawg</b>Maps</a> &copy; <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors",
minZoom: 0,
maxZoom: 22,
subdomains: "abcd",
accessToken:
"K1juMdkCgPLIjLt2KgXkeMDxenwtl9ZJqIZmNDbLoNU9P672uoA9ffNAty6UcoQU",
}
).addTo(this.map);
this.map.setView([userLat, userLon], 8); this.map.setView([userLat, userLon], 8);
for (let shop of this.shops) { for (let shop of this.shops) {
L.marker([shop.latitude, shop.longitude]) L.marker([shop.latitude, shop.longitude])
@ -267,18 +259,14 @@ export default defineComponent({
// Initialize map with markers for all shops in database // Initialize map with markers for all shops in database
initMap() { initMap() {
// View set with coords and zoom for France. // View set with coords and zoom for France.
this.map = L.map("map").setView([47, 2], 6); this.map = L.map("map", {attributionControl: false}).setView([47, 2], 6);
L.tileLayer( L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
"https://{s}.tile.jawg.io/jawg-sunny/{z}/{x}/{y}{r}.png?access-token={accessToken}", maxZoom: 16,
{ attribution: "&copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a>"
attribution: }).addTo(this.map);
"<a href='http://jawg.io' title='Tiles Courtesy of Jawg Maps' target='_blank'>&copy; <b>Jawg</b>Maps</a> &copy; <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", // Remove Ukrainian flag.
minZoom: 0, const myAttrControl = L.control.attribution().addTo(this.map);
maxZoom: 22, myAttrControl.setPrefix("<a href=\"https://leafletjs.com/\">Leaflet</a>");
accessToken:
"K1juMdkCgPLIjLt2KgXkeMDxenwtl9ZJqIZmNDbLoNU9P672uoA9ffNAty6UcoQU",
}
).addTo(this.map);
for (let shop of this.shops) { for (let shop of this.shops) {
L.marker([shop.latitude, shop.longitude]) L.marker([shop.latitude, shop.longitude])
.bindPopup(shop.name) .bindPopup(shop.name)

View file

@ -4,11 +4,6 @@
@section('description', __('Recherchez le magasin le plus près de chez vous commercialisant des produits de chez nous.')) @section('description', __('Recherchez le magasin le plus près de chez vous commercialisant des produits de chez nous.'))
@section('breadcrumb', request()->route()->getName()) @section('breadcrumb', request()->route()->getName())
@push('styles')
<link href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" rel="stylesheet" integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
crossorigin="" />
@endpush
@section('content') @section('content')
<div class="g-0 pb-md-5 position-relative hero"> <div class="g-0 pb-md-5 position-relative hero">
<img class="img-fluid" src="{{ Vite::asset('resources/assets/images/100LOCAL-V1.png') }}" alt="Logo 100% local"> <img class="img-fluid" src="{{ Vite::asset('resources/assets/images/100LOCAL-V1.png') }}" alt="Logo 100% local">
@ -27,15 +22,13 @@
</div> </div>
<!-- END breadcrumb --> <!-- END breadcrumb -->
</div> </div>
<div class="position-relative container pt-5"> <div class="position-relative container pt-5">
<div class="row"> <div class="row">
<section class="col-md-8 offset-md-2 stripes"> <section class="col-md-8 offset-md-2 stripes">
<h1 class="text-uppercase font-amatic font-amatic-48 text-center">{{ __('Retrouvez vos produits Lionor') }}<span <h1 class="text-uppercase font-amatic font-amatic-48 text-center">{{ __('Retrouvez vos produits Lionor') }}<span
class="font-amatic-red">{{ __('près de chez vous') }}</span></h1> class="font-amatic-red">{{ __('près de chez vous') }}</span></h1>
</section> </section>
</div> </div>
@if (now()->lessThan(\Carbon\Carbon::make('2024-07-01'))) @if (now()->lessThan(\Carbon\Carbon::make('2024-07-01')))
<div class="row my-4"> <div class="row my-4">
<div class="col-md-8 offset-md-2 col-lg-6 offset-lg-3"> <div class="col-md-8 offset-md-2 col-lg-6 offset-lg-3">
@ -45,7 +38,6 @@
</div> </div>
</div> </div>
@endif @endif
<div class="row search my-4"> <div class="row search my-4">
<div class="col-md-6 offset-md-3"> <div class="col-md-6 offset-md-3">
<form class="d-flex" id="address-form"> <form class="d-flex" id="address-form">
@ -55,12 +47,10 @@
</form> </form>
</div> </div>
</div> </div>
<!-- GRID --> <!-- GRID -->
<div class="row g-3"> <div class="row g-3">
<div class="col-lg-6 shops-module"> <div class="col-lg-6 shops-module">
<span class="shops-module-title text-uppercase">{{ __('Magasins') }}</span> <span class="shops-module-title text-uppercase">{{ __('Magasins') }}</span>
<div class="list-group shops-list" id="shops-list"> <div class="list-group shops-list" id="shops-list">
<button class="list-group-item list-group-item-action d-flex align-items-center justify-content-between d-none" <button class="list-group-item list-group-item-action d-flex align-items-center justify-content-between d-none"
id="shop-list-item"> id="shop-list-item">
@ -105,10 +95,4 @@
</div> </div>
<!-- END GRID --> <!-- END GRID -->
</div> </div>
@endsection @endsection
@push('scripts')
<script nonce="{{ $nonce ?? '' }}" src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"
integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM=" crossorigin=""></script>
@endpush

View file

@ -1,11 +1,12 @@
import legacy from "@vitejs/plugin-legacy";
import vue from "@vitejs/plugin-vue";
import laravel from "laravel-vite-plugin";
import path from "path";
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import checker from "vite-plugin-checker"; import checker from "vite-plugin-checker";
import copy from "rollup-plugin-copy";
import eslint from "vite-plugin-eslint"; import eslint from "vite-plugin-eslint";
import laravel from "laravel-vite-plugin";
import legacy from "@vitejs/plugin-legacy";
import path from "path";
import stylelint from "vite-plugin-stylelint"; import stylelint from "vite-plugin-stylelint";
import vue from "@vitejs/plugin-vue";
export default defineConfig({ export default defineConfig({
build: { build: {
@ -99,6 +100,19 @@ export default defineConfig({
targets: "last 3 version, not dead, >0.3%", targets: "last 3 version, not dead, >0.3%",
renderLegacyChunks: false, renderLegacyChunks: false,
}), }),
copy({
targets: [
{
src: [
path.normalize("node_modules/leaflet/dist/images/marker-icon.png"),
path.normalize("node_modules/leaflet/dist/images/marker-shadow.png"),
],
dest: path.normalize("public")
},
],
copyOnce: true,
verbose: true
}),
], ],
resolve: { resolve: {
extensions: ["*", ".js", ".ts", ".vue"], extensions: ["*", ".js", ".ts", ".vue"],