init
This commit is contained in:
79
.env
79
.env
@@ -16,33 +16,80 @@
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
APP_ENV=dev
|
||||
APP_SECRET=
|
||||
APP_SECRET=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
||||
APP_SHARE_DIR=var/share
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> symfony/routing ###
|
||||
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
|
||||
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
|
||||
DEFAULT_URI=http://localhost
|
||||
DEFAULT_URI=https://esyweb.local
|
||||
###< symfony/routing ###
|
||||
|
||||
###> doctrine/doctrine-bundle ###
|
||||
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
||||
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
|
||||
#
|
||||
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data_%kernel.environment%.db"
|
||||
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
|
||||
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
|
||||
DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8"
|
||||
DATABASE_URL="postgresql://app:secret@pgbouncer:6432/e_ticket?serverVersion=16&charset=utf8"
|
||||
###< doctrine/doctrine-bundle ###
|
||||
|
||||
###> symfony/messenger ###
|
||||
# Choose one of the transports below
|
||||
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
|
||||
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
|
||||
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
|
||||
MESSENGER_TRANSPORT_DSN=redis://redis:6379/messages
|
||||
###< symfony/messenger ###
|
||||
|
||||
###> session ###
|
||||
SESSION_HANDLER_DSN=redis://redis:6379/1
|
||||
###< session ###
|
||||
|
||||
###> cache ###
|
||||
REDIS_CACHE_DSN=redis://redis:6379/2
|
||||
###< cache ###
|
||||
|
||||
###> symfony/mailer ###
|
||||
MAILER_DSN=null://null
|
||||
MAILER_DSN=smtp://mailpit:1025
|
||||
###< symfony/mailer ###
|
||||
|
||||
###> vite ###
|
||||
# 0 = dev (HMR via localhost:5173), 1 = prod (manifest build)
|
||||
VITE_LOAD=0
|
||||
REAL_MAIL=0
|
||||
###< vite ###
|
||||
STRIPE_PK=
|
||||
STRIPE_SK=
|
||||
STRIPE_WEBHOOK_SECRET=
|
||||
STRIPE_WEBHOOK_SECRET_CONNECT=
|
||||
STRIPE_MODE=test
|
||||
STRIPE_FEE_RATE=0.015
|
||||
STRIPE_FEE_FIXED=25
|
||||
ADMIN_EMAIL=contact@e-cosplay.fr
|
||||
|
||||
###> SonarQube ###
|
||||
SONARQUBE_URL=https://sn.esy-web.dev
|
||||
SONARQUBE_BADGE_TOKEN=
|
||||
SONARQUBE_PROJECT_KEY=crm-ecosplay
|
||||
###< SonarQube ###
|
||||
|
||||
###> SSO E-Cosplay (Keycloak OIDC) ###
|
||||
OAUTH_KEYCLOAK_CLIENT_ID=e-ticket
|
||||
OAUTH_KEYCLOAK_CLIENT_SECRET=changeme
|
||||
OAUTH_KEYCLOAK_URL=https://auth.esy-web.dev
|
||||
OAUTH_KEYCLOAK_REALM=e-cosplay
|
||||
###< SSO E-Cosplay (Keycloak OIDC) ###
|
||||
|
||||
###> Keycloak Admin Service Account ###
|
||||
KEYCLOAK_ADMIN_CLIENT_ID=crm-ecosplay-admin
|
||||
KEYCLOAK_ADMIN_CLIENT_SECRET=
|
||||
###< Keycloak Admin Service Account ###
|
||||
|
||||
###> symfony/amazon-mailer ###
|
||||
# MAILER_DSN=ses://ACCESS_KEY:SECRET_KEY@default?region=eu-west-1
|
||||
# MAILER_DSN=ses+smtp://ACCESS_KEY:SECRET_KEY@default?region=eu-west-1
|
||||
###< symfony/amazon-mailer ###
|
||||
|
||||
###> stripe/stripe-php ###
|
||||
STRIPE_SECRET_KEY=sk_test_***
|
||||
###< stripe/stripe-php ###
|
||||
SMIME_PASSPHRASE=EVz5zNV8h4ndSLOCWO9JeaQnIertQm7k
|
||||
SECRET_ANALYTICS=
|
||||
|
||||
###> docuseal ###
|
||||
DOCUSEAL_URL=https://signature.esy-web.dev
|
||||
DOCUSEAL_API=
|
||||
DOCUSEAL_WEBHOOKS_SECRET_HEADER=X-Sign
|
||||
DOCUSEAL_WEBHOOKS_SECRET=
|
||||
###< docuseal ###
|
||||
|
||||
0
.gitea/.gitkeep
Normal file
0
.gitea/.gitkeep
Normal file
1
.gitea/CODEOWNERS
Normal file
1
.gitea/CODEOWNERS
Normal file
@@ -0,0 +1 @@
|
||||
* @jovann @e-cosplay
|
||||
353
.gitea/workflows/ci.yml
Normal file
353
.gitea/workflows/ci.yml
Normal file
@@ -0,0 +1,353 @@
|
||||
|
||||
j'ai gitea + sonarqube auto hébger tu me conseiler quoi en plus pour analyser le code php
|
||||
|
||||
13:35
|
||||
Bonne question ! Avec Gitea + SonarQube déjà en place, voici ce que je te recommanderais pour compléter ta chaîne d'analyse PHP :
|
||||
|
||||
Analyse statique complémentaire — Tu utilises déjà PHPStan via SonarQube, mais le lancer aussi en standalone (niveau max) te donne un feedback plus rapide dans ta CI. Psalm est une alternative/complément intéressant, surtout pour l'analyse de type et la détection de dead code. Les deux peuvent coexister.
|
||||
|
||||
Style & standards — PHP CS Fixer ou PHP_CodeSniffer pour enforcer un coding standard (PSR-12 ou custom). PHP CS Fixer s'intègre bien dans un pre-commit hook ou un job CI Gitea Actions/Drone.
|
||||
|
||||
Sécurité — Snyk ou Trivy pour scanner les dépendances Composer (CVE). Trivy est self-hostable et peut aussi scanner tes images Docker, ce qui colle bien avec ton stack. Semgrep est aussi un bon choix pour des règles de sécurité custom sur le code PHP (OWASP patterns, injections SQL, XSS).
|
||||
|
||||
Complexité & dette technique — PHPMetrics génère des rapports HTML visuels sur la complexité cyclomatique, le couplage, la maintenabilité. Ça complète bien SonarQube avec une vue plus "architecturale". dePHPend analyse les dépendances entre classes/packages pour détecter les couplages problématiques.
|
||||
|
||||
Tests & couverture — Si pas déjà en place, PHPUnit + Infection (mutation testing) pour mesurer la qualité réelle de tes tests, pas juste le coverage brut. SonarQube peut ingérer les rapports de coverage PHPUnit.
|
||||
|
||||
En priorité pour ton contexte (multi-tenant, ~85 sites ESY-WEB), je partirais sur :
|
||||
|
||||
PHPStan niveau max en CI (si pas déjà fait en standalone)
|
||||
Trivy (scan dépendances Composer + images Docker — tu as déjà le stack Docker)
|
||||
PHP CS Fixer en pre-commit
|
||||
PHPMetrics pour le reporting visuel
|
||||
Tout ça s'orchestre bien avec des Gitea Actions ou un pipeline Makefile, ce qui colle avec ton workflow habituel. Tu veux que je t'aide à mettre en place un de ces outils en particulier ?
|
||||
|
||||
|
||||
name: CI on: push: branches: - master - main pull_request: jobs: sonarqube: runs_on: ubuntu-latest services: database: image: postgres:16-alpine env: POSTGRES_USER: app POSTGRES_PASSWORD: secret POS
|
||||
|
||||
pasted
|
||||
|
||||
j'ai deja tout sa
|
||||
|
||||
13:36
|
||||
Ah ok, t'es déjà bien équipé ! Ton pipeline est solide. Voici ce qui manque et qui aurait une vraie valeur ajoutée :
|
||||
|
||||
Sécurité applicative — Semgrep pour de l'analyse SAST orientée patterns PHP (injections SQL, XSS, SSRF, deserialize unsafe). OWASP Dependency-Check couvre les dépendances, mais pas le code lui-même. Semgrep est gratuit en CLI et s'ajoute en une step.
|
||||
|
||||
Qualité / dette — PHPMetrics pour un rapport HTML visuel (complexité cyclomatique, couplage, maintenabilité par classe). SonarQube donne des métriques mais PHPMetrics a une vue "bubble chart" par classe qui aide à prioriser le refacto. Très rapide à ajouter, pas besoin de services.
|
||||
|
||||
Tests — Infection (mutation testing). Tu as déjà PHPUnit + coverage, mais le coverage seul ne dit pas si tes tests détectent vraiment les régressions. Infection mute ton code et vérifie que les tests cassent. Ça s'intègre bien avec le coverage.xml que tu génères déjà.
|
||||
|
||||
Infra/Docker — Trivy en remplacement ou complément de Hadolint. Hadolint lint les Dockerfiles, Trivy scanne les images buildées (CVE dans les packages OS + dépendances). Vu ton stack multi-container c'est pertinent.
|
||||
|
||||
Frontend — Lighthouse CI si tu as des pages publiques côté E-Cosplay. Perf, accessibilité, SEO en une step.
|
||||
|
||||
En résumé les ajouts concrets :
|
||||
|
||||
yaml
|
||||
- name: Semgrep SAST
|
||||
run: |
|
||||
pip install semgrep --break-system-packages
|
||||
semgrep scan --config=auto --json -o semgrep-report.json src/ || true
|
||||
|
||||
- name: PHPMetrics
|
||||
run: |
|
||||
composer global require phpmetrics/phpmetrics --no-interaction
|
||||
phpmetrics --report-html=phpmetrics-report src/
|
||||
|
||||
- name: Infection (mutation testing)
|
||||
run: |
|
||||
vendor/bin/infection --threads=4 --min-msi=50 --min-covered-msi=60 --logger-json=infection-report.json || true
|
||||
Semgrep est le plus impactant vu que t'as zéro SAST sur le code source actuellement — OWASP DC ne couvre que les dépendances. Tu veux que je t'intègre ça proprement dans ton workflow complet ?
|
||||
|
||||
|
||||
name: CI on: push: branches: - master - main pull_request: jobs: sonarqube: runs_on: ubuntu-latest services: database: image: postgres:16-alpine env: POSTGRES_USER: app POSTGRES_PASSWORD: secret POS
|
||||
|
||||
pasted
|
||||
|
||||
13:37
|
||||
Nickel, t'as intégré les trois. Ton pipeline est maintenant très complet. Quelques remarques d'optimisation :
|
||||
|
||||
Problème potentiel avec Infection — il a besoin du coverage.xml généré par PHPUnit, mais il faut lui passer explicitement. Vérifie que ton infection.json5 pointe bien dessus, sinon ajoute --coverage=coverage.xml ou mieux, utilise le flag --skip-initial-tests si tu veux qu'il réutilise le coverage existant.
|
||||
|
||||
PHPMetrics — composer global require peut être lent en CI. Une alternative plus rapide :
|
||||
|
||||
yaml
|
||||
- name: PHPMetrics
|
||||
run: |
|
||||
wget -qO phpmetrics.phar https://github.com/phpmetrics/PhpMetrics/releases/latest/download/phpmetrics.phar
|
||||
php phpmetrics.phar --report-html=phpmetrics-report src/
|
||||
Semgrep — pip install en CI c'est aussi un peu lent. L'image Docker officielle est plus rapide :
|
||||
|
||||
yaml
|
||||
- name: Semgrep SAST
|
||||
run: |
|
||||
docker run --rm -v "${GITHUB_WORKSPACE}:/src" semgrep/semgrep semgrep scan --config=auto --json -o /src/semgrep-report.json /src/src/ || true
|
||||
Mais vu que t'es sur Gitea Actions (pas GitHub), vérifie que le Docker-in-Docker fonctionne dans ton runner. Sinon le pip install reste le plus safe.
|
||||
|
||||
Ce qui manque pour boucler — tous ces rapports (semgrep, phpmetrics, infection, hadolint) sont générés mais pas exploités. Deux options :
|
||||
|
||||
SonarQube — configure sonar.externalIssuesReportPaths dans ton sonar-project.properties pour ingérer les JSON de Semgrep et Hadolint. SonarQube les affichera comme "external issues".
|
||||
Artifacts — upload les rapports comme artifacts de build pour les consulter après :
|
||||
yaml
|
||||
- name: Upload reports
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ci-reports
|
||||
path: |
|
||||
semgrep-report.json
|
||||
phpmetrics-report/
|
||||
infection-report.json
|
||||
hadolint-*.json
|
||||
dependency-check-report.*
|
||||
eslint-report.json
|
||||
phpstan-report.json
|
||||
Ça te permettrait de consulter le rapport PHPMetrics HTML directement. Tu veux que je te génère le sonar-project.properties adapté avec l'import des rapports externes ?
|
||||
|
||||
|
||||
name: CI on: push: branches: - master - main pull_request: jobs: sonarqube: runs_on: ubuntu-latest services: database: image: postgres:16-alpine env: POSTGRES_USER: app POSTGRES_PASSWORD: secret POS
|
||||
|
||||
pasted
|
||||
|
||||
13:38
|
||||
OK, quelques corrections à faire sur ton workflow actuel :
|
||||
|
||||
PHPMetrics — tu mélanges les deux approches. Tu fais composer global require mais ensuite php phpmetrics.phar (qui n'existe pas puisque t'as pas téléchargé le phar). Choisis l'un ou l'autre :
|
||||
|
||||
yaml
|
||||
# Option A : phar (plus rapide)
|
||||
- name: PHPMetrics
|
||||
run: |
|
||||
wget -qO phpmetrics.phar https://github.com/phpmetrics/PhpMetrics/releases/latest/download/phpmetrics.phar
|
||||
php phpmetrics.phar --report-html=phpmetrics-report src/
|
||||
|
||||
# Option B : composer global
|
||||
- name: PHPMetrics
|
||||
run: |
|
||||
composer global require phpmetrics/phpmetrics --no-interaction
|
||||
~/.composer/vendor/bin/phpmetrics --report-html=phpmetrics-report src/
|
||||
Semgrep Docker — attention, sur Gitea Actions le ${GITHUB_WORKSPACE} n'existe probablement pas. Selon ton runner Gitea, ça sera plutôt ${GITEA_WORKSPACE} ou ${{ github.workspace }} (si ton runner est compatible). Vérifie, sinon reviens au pip install qui est plus portable :
|
||||
|
||||
yaml
|
||||
- name: Semgrep SAST
|
||||
run: |
|
||||
pip install semgrep --break-system-packages
|
||||
semgrep scan --config=auto --json -o semgrep-report.json src/ || true
|
||||
Upload des artifacts + sonar-project.properties — tu veux que je te génère les deux fichiers ? Le sonar-project.properties avec l'import de tous tes rapports externes (Semgrep, PHPStan, ESLint, Hadolint, coverage), et la step d'upload artifacts à ajouter en fin de pipeline ?
|
||||
|
||||
sort tout le workflow stp
|
||||
|
||||
13:38
|
||||
Voici le workflow complet corrigé :
|
||||
|
||||
|
||||
Presenting files
|
||||
Presenting files
|
||||
|
||||
Workflow CI complet corrigé avec tous les outils d'analyse
|
||||
ci.yml
|
||||
|
||||
sonar-project.properties avec import de tous les rapports externes
|
||||
sonar-project.properties
|
||||
|
||||
Presenting file(s)...
|
||||
|
||||
|
||||
|
||||
Claude est une IA et peut faire des erreurs. Veuillez vérifier les réponses.
|
||||
Ci · YML
|
||||
Copier
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
runs_on: ubuntu-latest
|
||||
services:
|
||||
database:
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_USER: app
|
||||
POSTGRES_PASSWORD: secret
|
||||
POSTGRES_DB: crm_ecosplay
|
||||
options: >-
|
||||
--health-cmd "pg_isready -U app -d crm_ecosplay"
|
||||
--health-interval 5s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
options: >-
|
||||
--health-cmd "redis-cli ping"
|
||||
--health-interval 5s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:latest
|
||||
env:
|
||||
MEILI_MASTER_KEY: test
|
||||
MEILI_ENV: development
|
||||
env:
|
||||
DATABASE_URL: "postgresql://app:secret@database:5432/crm_ecosplay?serverVersion=16&charset=utf8"
|
||||
MESSENGER_TRANSPORT_DSN: "redis://redis:6379/messages"
|
||||
MAILER_DSN: "null://null"
|
||||
MEILISEARCH_URL: "http://meilisearch:7700"
|
||||
MEILISEARCH_API_KEY: "test"
|
||||
APP_ENV: test
|
||||
|
||||
steps:
|
||||
# ─── Setup ───────────────────────────────────────────────
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.4'
|
||||
extensions: intl, pdo_pgsql, zip, gd, redis, imagick
|
||||
coverage: xdebug
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
|
||||
# ─── Dependencies ────────────────────────────────────────
|
||||
- name: Install PHP dependencies
|
||||
run: composer install --no-interaction --prefer-dist
|
||||
|
||||
- name: Install JS dependencies
|
||||
run: |
|
||||
bun install
|
||||
npm install
|
||||
|
||||
# ─── Security audits ─────────────────────────────────────
|
||||
- name: Composer security audit
|
||||
run: composer audit
|
||||
|
||||
# ─── Linting ─────────────────────────────────────────────
|
||||
- name: Lint Twig
|
||||
run: php bin/console lint:twig templates/
|
||||
|
||||
- name: Lint YAML
|
||||
run: php bin/console lint:yaml config/
|
||||
|
||||
- name: Lint Container
|
||||
run: php bin/console lint:container
|
||||
|
||||
- name: PHP CS Fixer
|
||||
run: vendor/bin/php-cs-fixer fix --dry-run --diff
|
||||
|
||||
- name: ESLint report
|
||||
run: bunx eslint assets/ --ext .js,.ts -f json -o eslint-report.json || true
|
||||
|
||||
- name: Stylelint
|
||||
run: bunx stylelint "assets/**/*.scss"
|
||||
|
||||
# ─── Static analysis ─────────────────────────────────────
|
||||
- name: PHPStan report
|
||||
run: vendor/bin/phpstan analyse src/ --level=6 --no-progress --error-format=json > phpstan-report.json || true
|
||||
|
||||
- name: Semgrep SAST
|
||||
run: |
|
||||
pip install semgrep --break-system-packages
|
||||
semgrep scan --config=auto --json -o semgrep-report.json src/ || true
|
||||
|
||||
# ─── Build ───────────────────────────────────────────────
|
||||
- name: Build assets
|
||||
run: bun run build
|
||||
|
||||
# ─── Tests ───────────────────────────────────────────────
|
||||
- name: JS tests with coverage
|
||||
run: bun run test:coverage
|
||||
|
||||
- name: Create test database
|
||||
run: php bin/console doctrine:database:create --env=test --if-not-exists
|
||||
|
||||
- name: Create database schema
|
||||
run: php bin/console doctrine:schema:create --env=test
|
||||
|
||||
- name: PHPUnit with coverage
|
||||
run: vendor/bin/phpunit --testdox --coverage-clover coverage.xml --coverage-text
|
||||
|
||||
- name: Infection (mutation testing)
|
||||
run: |
|
||||
vendor/bin/infection \
|
||||
--threads=4 \
|
||||
--skip-initial-tests \
|
||||
--coverage=. \
|
||||
--min-msi=50 \
|
||||
--min-covered-msi=60 \
|
||||
--logger-json=infection-report.json || true
|
||||
|
||||
# ─── Metrics ─────────────────────────────────────────────
|
||||
- name: PHPMetrics
|
||||
run: |
|
||||
wget -qO phpmetrics.phar https://github.com/phpmetrics/PhpMetrics/releases/latest/download/phpmetrics.phar
|
||||
php phpmetrics.phar --report-html=phpmetrics-report src/
|
||||
|
||||
# ─── Docker linting ──────────────────────────────────────
|
||||
- name: Hadolint
|
||||
run: |
|
||||
wget -qO hadolint https://github.com/hadolint/hadolint/releases/latest/download/hadolint-Linux-x86_64
|
||||
chmod +x hadolint
|
||||
./hadolint docker/php/dev/Dockerfile -f json > hadolint-dev.json || true
|
||||
./hadolint docker/php/prod/Dockerfile -f json > hadolint-prod.json || true
|
||||
|
||||
# ─── Dependency vulnerability scan ───────────────────────
|
||||
- name: OWASP Dependency-Check
|
||||
uses: dependency-check/Dependency-Check_Action@main
|
||||
with:
|
||||
project: 'crm-ecosplay'
|
||||
path: '.'
|
||||
format: 'JSON,HTML'
|
||||
args: >
|
||||
--scan composer.lock
|
||||
--scan package.json
|
||||
--out .
|
||||
--disableAssembly
|
||||
--nvdApiKey ${{ secrets.NVD_API_KEY }}
|
||||
continue-on-error: true
|
||||
|
||||
- name: Rename Dependency-Check reports
|
||||
run: |
|
||||
mv dependency-check-report.json dc-report.json 2>/dev/null || true
|
||||
mv dependency-check-report.html dc-report.html 2>/dev/null || true
|
||||
|
||||
# ─── SonarQube ───────────────────────────────────────────
|
||||
- name: SonarQube Scan
|
||||
uses: sonarsource/sonarqube-scan-action@v5
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_HOST_URL: https://sn.esy-web.dev
|
||||
|
||||
# ─── Upload reports ──────────────────────────────────────
|
||||
- name: Upload CI reports
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: ci-reports
|
||||
retention-days: 30
|
||||
path: |
|
||||
coverage.xml
|
||||
phpstan-report.json
|
||||
eslint-report.json
|
||||
semgrep-report.json
|
||||
infection-report.json
|
||||
hadolint-dev.json
|
||||
hadolint-prod.json
|
||||
dc-report.*
|
||||
phpmetrics-report/
|
||||
|
||||
20
.gitea/workflows/deploy.yml
Normal file
20
.gitea/workflows/deploy.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
name: Deploy to production
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 1,22 * * *'
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs_on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup SSH key
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
|
||||
chmod 600 ~/.ssh/id_ed25519
|
||||
ssh-keyscan 34.90.187.4 >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Deploy
|
||||
run: ssh bot@34.90.187.4 "cd /var/www/crm-ecosplay && ansible-playbook ansible/deploy.yml -i ansible/hosts.ini --vault-password-file <(echo '${{ secrets.ANSIBLE_VAULT_PASSWORD }}')"
|
||||
116
.gitea/workflows/sonarqube.yml
Normal file
116
.gitea/workflows/sonarqube.yml
Normal file
@@ -0,0 +1,116 @@
|
||||
name: SonarQube Full Scan
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
scan:
|
||||
runs_on: ubuntu-latest
|
||||
services:
|
||||
database:
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_USER: app
|
||||
POSTGRES_PASSWORD: secret
|
||||
POSTGRES_DB: crm_ecosplay
|
||||
options: >-
|
||||
--health-cmd "pg_isready -U app -d crm_ecosplay"
|
||||
--health-interval 5s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
options: >-
|
||||
--health-cmd "redis-cli ping"
|
||||
--health-interval 5s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:latest
|
||||
env:
|
||||
MEILI_MASTER_KEY: test
|
||||
MEILI_ENV: development
|
||||
env:
|
||||
DATABASE_URL: "postgresql://app:secret@database:5432/crm_ecosplay?serverVersion=16&charset=utf8"
|
||||
MESSENGER_TRANSPORT_DSN: "redis://redis:6379/messages"
|
||||
MAILER_DSN: "null://null"
|
||||
MEILISEARCH_URL: "http://meilisearch:7700"
|
||||
MEILISEARCH_API_KEY: "test"
|
||||
APP_ENV: test
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.4'
|
||||
extensions: intl, pdo_pgsql, zip, gd, redis, imagick
|
||||
coverage: xdebug
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
|
||||
- name: Install PHP dependencies
|
||||
run: composer install --no-interaction --prefer-dist
|
||||
|
||||
- name: Install JS dependencies
|
||||
run: bun install
|
||||
|
||||
- name: JS tests with coverage
|
||||
run: bun run test:coverage
|
||||
|
||||
- name: PHPStan report
|
||||
run: vendor/bin/phpstan analyse src/ --level=6 --no-progress --error-format=json > phpstan-report.json || true
|
||||
|
||||
- name: Build assets
|
||||
run: bun run build
|
||||
|
||||
- name: Create test database
|
||||
run: php bin/console doctrine:database:create --env=test --if-not-exists
|
||||
|
||||
- name: Create database schema
|
||||
run: php bin/console doctrine:schema:create --env=test
|
||||
|
||||
- name: PHPUnit with coverage
|
||||
run: vendor/bin/phpunit --coverage-clover coverage.xml
|
||||
|
||||
- name: ESLint report
|
||||
run: bunx eslint assets/ --ext .js,.ts -f json -o eslint-report.json || true
|
||||
|
||||
- name: Hadolint
|
||||
run: |
|
||||
wget -qO hadolint https://github.com/hadolint/hadolint/releases/latest/download/hadolint-Linux-x86_64
|
||||
chmod +x hadolint
|
||||
./hadolint docker/php/dev/Dockerfile -f json > hadolint-dev.json || true
|
||||
./hadolint docker/php/prod/Dockerfile -f json > hadolint-prod.json || true
|
||||
|
||||
- name: OWASP Dependency-Check
|
||||
uses: dependency-check/Dependency-Check_Action@main
|
||||
with:
|
||||
project: 'crm-ecosplay'
|
||||
path: '.'
|
||||
format: 'JSON,HTML'
|
||||
args: >
|
||||
--scan composer.lock
|
||||
--scan package.json
|
||||
--out .
|
||||
--disableAssembly
|
||||
continue-on-error: true
|
||||
|
||||
- name: SonarQube Scan
|
||||
uses: sonarsource/sonarqube-scan-action@v5
|
||||
with:
|
||||
args: >
|
||||
-Dsonar.qualitygate.wait=true
|
||||
-Dsonar.scm.forceReloadAll=true
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_HOST_URL: https://sn.esy-web.dev
|
||||
38
.gitignore
vendored
38
.gitignore
vendored
@@ -1,4 +1,3 @@
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
/.env.local
|
||||
/.env.local.php
|
||||
@@ -14,7 +13,44 @@
|
||||
/.phpunit.cache/
|
||||
###< phpunit/phpunit ###
|
||||
|
||||
/public/build/
|
||||
/public/uploads/
|
||||
/public/.update
|
||||
docker-compose-prod.yml
|
||||
docker/pgsql/pgbouncer.ini
|
||||
docker/pgsql/userlist.txt
|
||||
node_modules/
|
||||
.idea/
|
||||
/cert/
|
||||
/config/cert/private-key.pem
|
||||
/public/media/
|
||||
/coverage/
|
||||
/coverage-clover.xml
|
||||
|
||||
###> friendsofphp/php-cs-fixer ###
|
||||
/.php-cs-fixer.php
|
||||
/.php-cs-fixer.cache
|
||||
###< friendsofphp/php-cs-fixer ###
|
||||
|
||||
###> symfony/asset-mapper ###
|
||||
/public/assets/
|
||||
/assets/vendor/
|
||||
###< symfony/asset-mapper ###
|
||||
|
||||
###> spomky-labs/pwa-bundle ###
|
||||
/public/sw.js
|
||||
/public/workbox
|
||||
/public/idb
|
||||
/public/pwa
|
||||
/public/favicon.ico
|
||||
/public/site.webmanifest
|
||||
/public/site.*.webmanifest
|
||||
###< spomky-labs/pwa-bundle ###
|
||||
|
||||
###> liip/imagine-bundle ###
|
||||
/public/media/cache/
|
||||
###< liip/imagine-bundle ###
|
||||
|
||||
###> phpstan/phpstan ###
|
||||
phpstan.neon
|
||||
###< phpstan/phpstan ###
|
||||
|
||||
17
.php-cs-fixer.dist.php
Normal file
17
.php-cs-fixer.dist.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
$finder = (new PhpCsFixer\Finder())
|
||||
->in(__DIR__)
|
||||
->exclude('var')
|
||||
->notPath([
|
||||
'config/bundles.php',
|
||||
'config/reference.php',
|
||||
])
|
||||
;
|
||||
|
||||
return (new PhpCsFixer\Config())
|
||||
->setRules([
|
||||
'@Symfony' => true,
|
||||
])
|
||||
->setFinder($finder)
|
||||
;
|
||||
31
AGENT.md
Normal file
31
AGENT.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# AGENT.md
|
||||
|
||||
## Interdiction generale
|
||||
|
||||
**Aucun agent IA, assistant de code, ou outil automatise n'est autorise a modifier, committer, pousser, supprimer ou alterer de quelque maniere que ce soit les fichiers de ce depot.**
|
||||
|
||||
Cela inclut, sans s'y limiter :
|
||||
|
||||
- La modification de fichiers existants
|
||||
- La creation de nouveaux fichiers
|
||||
- La suppression de fichiers
|
||||
- Les commits et pushs Git
|
||||
- L'ouverture de pull requests ou d'issues
|
||||
- La modification de la configuration du projet
|
||||
- L'execution de commandes destructrices
|
||||
|
||||
## Portee
|
||||
|
||||
Cette interdiction s'applique a tous les agents IA et outils automatises, y compris mais sans s'y limiter :
|
||||
|
||||
- Claude Code / Claude
|
||||
- GitHub Copilot
|
||||
- Cursor
|
||||
- Windsurf
|
||||
- Devin
|
||||
- OpenAI Codex
|
||||
- Tout autre assistant IA ou bot
|
||||
|
||||
## Exceptions
|
||||
|
||||
Aucune exception. Toute intervention IA sur ce depot est strictement interdite sauf autorisation explicite et ecrite du proprietaire du projet.
|
||||
229
Makefile
Normal file
229
Makefile
Normal file
@@ -0,0 +1,229 @@
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
## —— Help ————————————————————————————————————————
|
||||
help: ## Affiche la liste des commandes disponibles
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
## —— Docker ——————————————————————————————————————
|
||||
build_dev: ## Build les images Docker pour le dev
|
||||
docker compose -f docker-compose-dev.yml build
|
||||
|
||||
build_prod: ## Build les images Docker pour la prod
|
||||
docker compose -f docker-compose-prod.yml build
|
||||
|
||||
start_dev: ## Lance les containers dev
|
||||
docker compose -f docker-compose-dev.yml up
|
||||
|
||||
start_prod: ## Lance les containers prod en background
|
||||
docker compose -f docker-compose-prod.yml up -d
|
||||
|
||||
stop_dev: ## Arrete les containers dev
|
||||
docker compose -f docker-compose-dev.yml down
|
||||
|
||||
purge_dev: ## Arrete et purge les containers dev (volumes inclus)
|
||||
docker compose -f docker-compose-dev.yml down -v
|
||||
|
||||
stop_prod: ## Arrete les containers prod
|
||||
docker compose -f docker-compose-prod.yml down
|
||||
|
||||
## —— Git ——————————————————————————————————————————
|
||||
pull_dev: ## Pull les images Docker dev
|
||||
docker compose -f docker-compose-dev.yml pull
|
||||
|
||||
pull_prod: ## Pull les images Docker prod
|
||||
docker compose -f docker-compose-prod.yml pull
|
||||
|
||||
## —— Ansible —————————————————————————————————————
|
||||
deploy_prod: ## Deploy en prod via Ansible (demande le vault password)
|
||||
ansible-playbook ansible/deploy.yml -i ansible/hosts.ini --ask-vault-pass
|
||||
|
||||
## —— Install ——————————————————————————————————————
|
||||
install_dev: ## Install les dependances dev via Docker
|
||||
docker compose -f docker-compose-dev.yml exec php composer install
|
||||
docker compose -f docker-compose-dev.yml exec bun bun install
|
||||
|
||||
install_prod: ## Install les dependances et build les assets pour la prod
|
||||
docker compose -f docker-compose-prod.yml exec php composer install --no-dev --optimize-autoloader
|
||||
bun install
|
||||
bun run build
|
||||
|
||||
## —— Tests ————————————————————————————————————————
|
||||
test_db_create: ## Cree la base de donnees de test
|
||||
docker compose -f docker-compose-dev.yml exec database psql -U app -d crm_ecosplay -tc "SELECT 1 FROM pg_database WHERE datname = 'crm_ecosplay_test'" | grep -q 1 || \
|
||||
docker compose -f docker-compose-dev.yml exec database psql -U app -d crm_ecosplay -c "CREATE DATABASE crm_ecosplay_test"
|
||||
|
||||
test_db_schema: ## Cree/met a jour le schema de la base de test
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/console doctrine:schema:update --force --env=test
|
||||
|
||||
test_db_migrate: ## Execute les migrations sur la base de test
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/console doctrine:migrations:migrate --no-interaction --env=test
|
||||
|
||||
test_db_reset: ## Supprime et recree la base de test depuis zero
|
||||
docker compose -f docker-compose-dev.yml exec database psql -U app -d crm_ecosplay -c "DROP DATABASE IF EXISTS crm_ecosplay_test"
|
||||
docker compose -f docker-compose-dev.yml exec database psql -U app -d crm_ecosplay -c "CREATE DATABASE crm_ecosplay_test"
|
||||
$(MAKE) test_db_schema
|
||||
|
||||
test_db_setup: ## Setup complet de la base de test (cree si besoin + schema)
|
||||
$(MAKE) test_db_create
|
||||
$(MAKE) test_db_schema
|
||||
|
||||
run_test: ## Lance les tests PHP et JS via Docker dev
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/phpunit
|
||||
docker compose -f docker-compose-dev.yml exec bun bun run test
|
||||
|
||||
run_test_php: ## Lance uniquement les tests PHP via Docker dev
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/phpunit
|
||||
|
||||
run_test_js: ## Lance uniquement les tests JS via Docker dev
|
||||
docker compose -f docker-compose-dev.yml exec bun bun run test
|
||||
|
||||
run_test_coverage_php: ## Lance les tests PHP avec couverture via Docker dev
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/phpunit --coverage-text --coverage-html=coverage/php
|
||||
|
||||
run_test_coverage_js: ## Lance les tests JS avec couverture via Docker dev
|
||||
docker compose -f docker-compose-dev.yml exec bun bun run test -- --coverage
|
||||
|
||||
run_test_file: ## Lance un fichier de test PHP specifique (usage: make run_test_file FILE=tests/Service/AuditServiceTest.php)
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/phpunit $(FILE)
|
||||
|
||||
## —— PWA —————————————————————————————————————————
|
||||
pwa_dev: ## Compile les assets PWA en dev via Docker
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/console pwa:compile
|
||||
|
||||
pwa_prod: ## Compile les assets PWA en prod via Docker
|
||||
docker compose -f docker-compose-prod.yml exec php php bin/console pwa:compile --env=prod
|
||||
|
||||
## —— Traductions ——————————————————————————————————
|
||||
trans: ## Traduit les fichiers YAML FR vers EN/ES/DE/IT via LibreTranslate (Docker dev)
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/console app:translate
|
||||
docker compose -f docker-compose-dev.yml stop libretranslate
|
||||
|
||||
trans_prod: ## Traduit les fichiers YAML FR vers EN/ES/DE/IT via LibreTranslate (Docker prod)
|
||||
docker compose -f docker-compose-prod.yml exec -T php php bin/console app:translate --env=prod
|
||||
docker compose -f docker-compose-prod.yml stop libretranslate
|
||||
|
||||
## —— Symfony ——————————————————————————————————————
|
||||
entity: ## Creer ou modifier une entite via Docker dev
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/console make:entity
|
||||
|
||||
## —— Database ——————————————————————————————————————
|
||||
migration_dev: ## Genere une migration via Docker dev
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/console make:migration
|
||||
|
||||
migrate_dev: ## Execute les migrations via Docker dev
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/console doctrine:migrations:migrate --no-interaction
|
||||
|
||||
force_sql_dev: ## Force la mise a jour du schema de la base de donnees dev
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/console doctrine:schema:update --force
|
||||
|
||||
migrate_prod: ## Execute les migrations en prod via Docker
|
||||
docker compose -f docker-compose-prod.yml exec php php bin/console doctrine:migrations:migrate --no-interaction --env=prod
|
||||
|
||||
## —— Cache ————————————————————————————————————————
|
||||
clear_prod: ## Clear le cache Symfony et le pool opcache en prod via Docker
|
||||
docker compose -f docker-compose-prod.yml exec php php bin/console cache:clear --env=prod
|
||||
docker compose -f docker-compose-prod.yml exec php php bin/console cache:pool:clear --all --env=prod
|
||||
|
||||
purge_liip_dev: ## Purge le cache Liip Imagine en dev via Docker
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/console liip:imagine:cache:remove
|
||||
|
||||
purge_liip_prod: ## Purge le cache Liip Imagine en prod via Docker
|
||||
docker compose -f docker-compose-prod.yml exec php php bin/console liip:imagine:cache:remove --env=prod
|
||||
|
||||
## —— Maintenance ——————————————————————————————————
|
||||
maintenance_on: ## Active le mode maintenance
|
||||
touch public/.update
|
||||
|
||||
maintenance_off: ## Desactive le mode maintenance
|
||||
rm -f public/.update
|
||||
|
||||
|
||||
## —— Qualite ──────────────────────────────────────
|
||||
qa: lint phpstan cs_check semgrep ## Lance tous les checks qualite (lint + analyse + sécurité)
|
||||
|
||||
qa_full: qa test_coverage infection phpmetrics ## Lance la suite complète (qa + tests coverage + mutation + metrics)
|
||||
|
||||
lint: ## Lance tous les linters (Twig, YAML, Container, ESLint, Stylelint)
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/console lint:twig templates/
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/console lint:yaml config/
|
||||
docker compose -f docker-compose-dev.yml exec php php bin/console lint:container
|
||||
docker compose -f docker-compose-dev.yml exec bun bunx eslint assets/ --ext .js,.ts
|
||||
docker compose -f docker-compose-dev.yml exec bun bunx stylelint "assets/**/*.scss"
|
||||
|
||||
phpstan: ## Lance PHPStan niveau 6
|
||||
docker compose -f docker-compose-dev.yml exec php vendor/bin/phpstan analyse src/ --level=6 --memory-limit=512M
|
||||
|
||||
phpstan_report: ## Lance PHPStan et genere le rapport JSON pour SonarQube
|
||||
docker compose -f docker-compose-dev.yml exec php sh -c 'mkdir -p var/reports && vendor/bin/phpstan analyse src/ --level=6 --memory-limit=512M --no-progress --error-format=json > var/reports/phpstan-report.json || true'
|
||||
|
||||
cs_check: ## Verifie le code style (dry-run)
|
||||
docker compose -f docker-compose-dev.yml exec php vendor/bin/php-cs-fixer fix --dry-run --diff
|
||||
|
||||
cs_fix: ## Corrige automatiquement le code style
|
||||
docker compose -f docker-compose-dev.yml exec php vendor/bin/php-cs-fixer fix
|
||||
|
||||
eslint: ## Lance ESLint sur les assets JS/TS
|
||||
docker compose -f docker-compose-dev.yml exec bun bunx eslint assets/ --ext .js,.ts
|
||||
|
||||
eslint_fix: ## Corrige automatiquement les erreurs ESLint
|
||||
docker compose -f docker-compose-dev.yml exec bun bunx eslint assets/ --ext .js,.ts --fix
|
||||
|
||||
eslint_report: ## Lance ESLint et genere le rapport JSON pour SonarQube
|
||||
docker compose -f docker-compose-dev.yml exec bun sh -c 'mkdir -p var/reports && bunx eslint assets/ --ext .js,.ts -f json -o var/reports/eslint-report.json || true'
|
||||
|
||||
stylelint: ## Lance Stylelint sur les fichiers SCSS
|
||||
docker compose -f docker-compose-dev.yml exec bun bunx stylelint "assets/**/*.scss"
|
||||
|
||||
stylelint_fix: ## Corrige automatiquement les erreurs Stylelint
|
||||
docker compose -f docker-compose-dev.yml exec bun bunx stylelint "assets/**/*.scss" --fix
|
||||
|
||||
semgrep: ## Lance Semgrep SAST sur src/
|
||||
docker compose -f docker-compose-dev.yml exec php sh -c 'pip install semgrep --break-system-packages -q && semgrep scan --config=auto src/'
|
||||
|
||||
semgrep_report:
|
||||
mkdir -p var/reports
|
||||
# 1. On garde ton scan Docker (il marche très bien)
|
||||
docker run --rm \
|
||||
--user $(shell id -u):$(shell id -g) \
|
||||
-v "$(PWD):/src" \
|
||||
returntocorp/semgrep \
|
||||
semgrep scan --config=auto --json -o var/reports/semgrep-raw.json src/ || true
|
||||
|
||||
# 2. Conversion JQ simplifiée (on ne garde QUE la ligne, pas la colonne)
|
||||
cat var/reports/semgrep-raw.json | jq '{issues: [.results[] | {engineId: "semgrep", ruleId: .check_id, severity: (if .extra.severity == "ERROR" then "CRITICAL" else "MAJOR" end), type: "VULNERABILITY", primaryLocation: {message: .extra.message, filePath: .path, textRange: {startLine: .start.line}}}]}' > var/reports/semgrep-report.json
|
||||
test_coverage: ## Lance les tests PHP avec couverture (clover + HTML + JUnit)
|
||||
docker compose -f docker-compose-dev.yml exec php sh -c 'mkdir -p var/reports && php bin/phpunit --testdox --log-junit var/reports/phpunit.xml --coverage-clover var/reports/coverage.xml --coverage-html var/reports/coverage-html --coverage-text'
|
||||
|
||||
infection: ## Lance Infection (mutation testing) sur les tests PHP
|
||||
docker compose -f docker-compose-dev.yml exec php sh -c 'mkdir -p var/reports && vendor/bin/infection --threads=4 --min-msi=50 --min-covered-msi=60 --logger-json=var/reports/infection-report.json || true'
|
||||
|
||||
infection_full: test_coverage infection ## Lance les tests avec couverture puis Infection
|
||||
|
||||
phpmetrics: ## Genere le rapport PHPMetrics HTML
|
||||
docker compose -f docker-compose-dev.yml exec php sh -c 'mkdir -p var/reports && curl -sLo /tmp/phpmetrics.phar https://github.com/phpmetrics/PhpMetrics/releases/latest/download/phpmetrics.phar && php /tmp/phpmetrics.phar --report-html=var/reports/phpmetrics-report src/'
|
||||
|
||||
hadolint: ## Lance Hadolint sur les Dockerfiles
|
||||
docker run --rm -v "$(PWD):/app" -w /app hadolint/hadolint hadolint docker/php/dev/Dockerfile
|
||||
docker run --rm -v "$(PWD):/app" -w /app hadolint/hadolint hadolint docker/php/prod/Dockerfile
|
||||
|
||||
hadolint_report: ## Lance Hadolint sur le Dockerfile prod et genere le rapport JSON
|
||||
mkdir -p var/reports
|
||||
# Use -i (interactive) and ensure no TTY is allocated to avoid escape characters
|
||||
docker run --rm -v "$(PWD):/app" -w /app hadolint/hadolint \
|
||||
hadolint docker/php/prod/Dockerfile -f json > var/reports/hadolint-raw.json || true
|
||||
|
||||
# Cleanup: Ensure the file isn't empty and contains valid JSON brackets
|
||||
@if [ ! -s var/reports/hadolint-raw.json ]; then echo "[]" > var/reports/hadolint-raw.json; fi
|
||||
# Optional: Strip potential Docker/System noise from the file
|
||||
@sed -i 's/^[^{|[ ]*//g' var/reports/hadolint-raw.json
|
||||
audit: ## Lance l'audit de securite Composer
|
||||
docker compose -f docker-compose-dev.yml exec php composer audit
|
||||
|
||||
reports: phpstan_report eslint_report semgrep_report test_coverage hadolint_report phpmetrics ## Genere tous les rapports pour SonarQube
|
||||
|
||||
## —— SonarQube ————————————————————————————————————
|
||||
sonar: reports ## Genere les rapports puis lance le scan SonarQube
|
||||
docker run --rm -v "$(PWD):/usr/src" -e SONAR_HOST_URL=https://sn.esy-web.dev -e SONAR_TOKEN=$(shell grep SONAR_TOKEN .env.local 2>/dev/null | cut -d= -f2 || echo "") sonarsource/sonar-scanner-cli
|
||||
|
||||
sonar_quick: ## Lance le scan SonarQube sans regenerer les rapports
|
||||
docker run --rm -v "$(PWD):/usr/src" -e SONAR_HOST_URL=https://sn.esy-web.dev -e SONAR_TOKEN=$(shell grep SONAR_TOKEN .env.local 2>/dev/null | cut -d= -f2 || echo "") sonarsource/sonar-scanner-cli
|
||||
0
ansible/.gitkeep
Normal file
0
ansible/.gitkeep
Normal file
34
ansible/backup.sh.j2
Normal file
34
ansible/backup.sh.j2
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
# CRM Ecosplay database backup script
|
||||
# Runs every 30 minutes via cron
|
||||
|
||||
BACKUP_DIR="/var/backups/crm-ecosplay"
|
||||
DATE=$(date +%Y%m%d_%H%M%S)
|
||||
FILENAME="crm_ecosplay_${DATE}.sql.gz"
|
||||
KEEP_DAYS=1
|
||||
|
||||
# Dump database via Docker
|
||||
docker compose -f /var/www/crm-ecosplay/docker-compose-prod.yml exec -T db-master pg_dump -U {{ db_user | default('crm-ecosplay') }} {{ db_name | default('crm-ecosplay') }} | gzip > "${BACKUP_DIR}/${FILENAME}"
|
||||
|
||||
# Check if backup was created
|
||||
if [ -f "${BACKUP_DIR}/${FILENAME}" ] && [ -s "${BACKUP_DIR}/${FILENAME}" ]; then
|
||||
echo "[$(date)] DB Backup OK: ${FILENAME} ($(du -h "${BACKUP_DIR}/${FILENAME}" | cut -f1))"
|
||||
else
|
||||
echo "[$(date)] ERROR: DB Backup failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Backup uploads
|
||||
UPLOADS_FILENAME="uploads_${DATE}.tar.gz"
|
||||
tar -czf "${BACKUP_DIR}/${UPLOADS_FILENAME}" -C /var/www/crm-ecosplay/public uploads 2>/dev/null
|
||||
|
||||
if [ -f "${BACKUP_DIR}/${UPLOADS_FILENAME}" ]; then
|
||||
echo "[$(date)] Uploads Backup OK: ${UPLOADS_FILENAME} ($(du -h "${BACKUP_DIR}/${UPLOADS_FILENAME}" | cut -f1))"
|
||||
else
|
||||
echo "[$(date)] WARNING: Uploads backup failed"
|
||||
fi
|
||||
|
||||
# Remove backups older than KEEP_DAYS days
|
||||
find "${BACKUP_DIR}" -name "crm_ecosplay_*.sql.gz" -mtime +${KEEP_DAYS} -delete
|
||||
find "${BACKUP_DIR}" -name "uploads_*.tar.gz" -mtime +${KEEP_DAYS} -delete
|
||||
echo "[$(date)] Cleaned backups older than ${KEEP_DAYS} days"
|
||||
53
ansible/caddy.j2
Normal file
53
ansible/caddy.j2
Normal file
@@ -0,0 +1,53 @@
|
||||
crm.e-cosplay.fr {
|
||||
tls {
|
||||
dns cloudflare cfat_rIHZqzCm9GKK3xVnQDNGfu6J91TseIDdTKeuWSFUdf6ccd31
|
||||
}
|
||||
|
||||
@static path /logo.png /favicon.ico /favicon.png /marker.png /screen.png /manifest.json /site.webmanifest /sw.js /unavailable.html /workbox/* /idb/* /build/* /uploads/* /pwa/*
|
||||
handle @static {
|
||||
root * /var/www/crm-crm-ecosplay/public
|
||||
file_server
|
||||
}
|
||||
|
||||
@maintenance file /var/www/crm-ecosplay/public/.update
|
||||
handle @maintenance {
|
||||
root * /var/www/crm-ecosplay/public
|
||||
rewrite * /maintenance.html
|
||||
file_server {
|
||||
status 503
|
||||
}
|
||||
}
|
||||
|
||||
handle {
|
||||
root * /var/www/crm-ecosplay/public
|
||||
php_fastcgi localhost:4568 localhost:4569 {
|
||||
root /app/public
|
||||
lb_policy round_robin
|
||||
trusted_proxies private_ranges
|
||||
dial_timeout 5s
|
||||
read_timeout 30s
|
||||
write_timeout 30s
|
||||
}
|
||||
file_server
|
||||
try_files {path} /index.php?{query}
|
||||
}
|
||||
|
||||
handle_errors {
|
||||
@unavailable expression `{err.status_code} in [502, 503]`
|
||||
handle @unavailable {
|
||||
root * /var/www/crm-ecosplay/public
|
||||
rewrite * /unavailable.html
|
||||
file_server
|
||||
}
|
||||
}
|
||||
|
||||
encode gzip
|
||||
|
||||
header {
|
||||
-Server
|
||||
}
|
||||
|
||||
log {
|
||||
output file /var/log/caddy/ticket.e-cosplay.fr.log
|
||||
}
|
||||
}
|
||||
278
ansible/deploy.yml
Normal file
278
ansible/deploy.yml
Normal file
@@ -0,0 +1,278 @@
|
||||
---
|
||||
# --- Server deployment ---
|
||||
- name: Deploy crm-ecosplay to production
|
||||
hosts: production
|
||||
become: true
|
||||
vars_files:
|
||||
- vault.yml
|
||||
|
||||
pre_tasks:
|
||||
- name: Enable maintenance mode
|
||||
command: make maintenance_on
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
|
||||
- name: Get Docker socket GID
|
||||
stat:
|
||||
path: /var/run/docker.sock
|
||||
register: docker_sock
|
||||
|
||||
- name: Set docker_gid fact
|
||||
set_fact:
|
||||
docker_gid: "{{ docker_sock.stat.gid }}"
|
||||
|
||||
- name: Generate analytics secret
|
||||
set_fact:
|
||||
analytics_secret: "{{ lookup('password', '/dev/null chars=ascii_lowercase,digits length=32') }}"
|
||||
|
||||
tasks:
|
||||
- name: Deploy .env.local
|
||||
template:
|
||||
src: env.local.j2
|
||||
dest: /var/www/crm-ecosplay/.env.local
|
||||
owner: bot
|
||||
group: bot
|
||||
mode: "0600"
|
||||
|
||||
- name: Ensure cert directory exists
|
||||
file:
|
||||
path: /var/www/crm-ecosplay/config/cert
|
||||
state: directory
|
||||
owner: bot
|
||||
group: bot
|
||||
mode: "0700"
|
||||
|
||||
- name: Deploy S/MIME private key
|
||||
copy:
|
||||
content: "{{ smime_private_key }}"
|
||||
dest: /var/www/crm-ecosplay/config/cert/private-key.pem
|
||||
owner: bot
|
||||
group: bot
|
||||
mode: "0600"
|
||||
|
||||
- name: Pull latest code
|
||||
command: git pull origin master
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
become_user: bot
|
||||
|
||||
- name: Deploy PgBouncer config
|
||||
template:
|
||||
src: pgbouncer.ini.j2
|
||||
dest: /var/www/crm-ecosplay/docker/pgsql/pgbouncer.ini
|
||||
owner: bot
|
||||
group: bot
|
||||
mode: "0644"
|
||||
|
||||
- name: Deploy PgBouncer userlist
|
||||
template:
|
||||
src: userlist.txt.j2
|
||||
dest: /var/www/crm-ecosplay/docker/pgsql/userlist.txt
|
||||
owner: bot
|
||||
group: bot
|
||||
mode: "0644"
|
||||
|
||||
- name: Deploy docker-compose-prod.yml
|
||||
template:
|
||||
src: docker-compose-prod.yml.j2
|
||||
dest: /var/www/crm-ecosplay/docker-compose-prod.yml
|
||||
owner: bot
|
||||
group: bot
|
||||
mode: "0600"
|
||||
|
||||
- name: Build Docker images
|
||||
command: make build_prod
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
|
||||
- name: Pull Docker images
|
||||
command: make pull_prod
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
|
||||
- name: Stop production containers
|
||||
command: make stop_prod
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
|
||||
- name: Start production containers
|
||||
command: make start_prod
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
|
||||
- name: Install PHP dependencies
|
||||
command: composer install --no-dev --optimize-autoloader
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
become_user: bot
|
||||
|
||||
- name: Install JS dependencies
|
||||
command: bun install
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
become_user: bot
|
||||
|
||||
- name: Build assets
|
||||
command: bun run build
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
become_user: bot
|
||||
|
||||
- name: Wait for database to be ready
|
||||
shell: |
|
||||
for i in $(seq 1 30); do
|
||||
docker compose -f docker-compose-prod.yml exec -T php php -r "new PDO('pgsql:host=pgbouncer;port=6432;dbname=crm-ecosplay','crm-ecosplay','{{ db_password }}');" 2>/dev/null && exit 0
|
||||
sleep 1
|
||||
done
|
||||
exit 1
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
|
||||
- name: Clear Symfony cache before migration
|
||||
command: docker compose -f docker-compose-prod.yml exec -T php php bin/console cache:clear --env=prod
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
|
||||
- name: Clear Redis cache pool (Doctrine L2 + app cache)
|
||||
command: docker compose -f docker-compose-prod.yml exec -T php php bin/console cache:pool:clear cache.app --env=prod
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
|
||||
- name: Run migrations
|
||||
command: make migrate_prod
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
|
||||
- name: Clear cache after migration
|
||||
command: make clear_prod
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
|
||||
- name: Compile PWA assets
|
||||
command: make pwa_prod
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
|
||||
- name: Ensure uploads directories exist with correct permissions
|
||||
file:
|
||||
path: "/var/www/crm-ecosplay/public/uploads/{{ item }}"
|
||||
state: directory
|
||||
owner: "1000"
|
||||
group: "1000"
|
||||
mode: "0755"
|
||||
recurse: true
|
||||
loop:
|
||||
- logos
|
||||
|
||||
- name: Ensure var/payouts directory exists
|
||||
file:
|
||||
path: /var/www/crm-ecosplay/var/payouts
|
||||
state: directory
|
||||
owner: "1000"
|
||||
group: "1000"
|
||||
mode: "0755"
|
||||
|
||||
- name: Ensure Caddy sites directory exists
|
||||
file:
|
||||
path: /etc/caddy/sites
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
|
||||
- name: Deploy Caddy config
|
||||
template:
|
||||
src: caddy.j2
|
||||
dest: /etc/caddy/sites/crm-ecosplay.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify: Reload Caddy
|
||||
|
||||
- name: Create backup directory
|
||||
file:
|
||||
path: /var/backups/crm-ecosplay
|
||||
state: directory
|
||||
owner: bot
|
||||
group: bot
|
||||
mode: "0750"
|
||||
|
||||
- name: Deploy backup script
|
||||
template:
|
||||
src: backup.sh.j2
|
||||
dest: /var/backups/crm-ecosplay/backup.sh
|
||||
owner: bot
|
||||
group: bot
|
||||
mode: "0750"
|
||||
|
||||
- name: Configure backup cron (every 30 minutes)
|
||||
cron:
|
||||
name: "crm-ecosplay database backup"
|
||||
minute: "*/30"
|
||||
job: "/var/backups/crm-ecosplay/backup.sh >> /var/log/crm-ecosplay-backup.log 2>&1"
|
||||
user: bot
|
||||
|
||||
- name: Configure expire pending orders cron (every 5 minutes)
|
||||
cron:
|
||||
name: "crm-ecosplay expire pending orders"
|
||||
minute: "*/5"
|
||||
job: "docker compose -f /var/www/crm-ecosplay/docker-compose-prod.yml exec -T php php bin/console app:orders:expire-pending --env=prod >> /var/log/crm-ecosplay-expire-orders.log 2>&1"
|
||||
user: bot
|
||||
|
||||
- name: Configure messenger monitor cron (every hour)
|
||||
cron:
|
||||
name: "crm-ecosplay messenger monitor"
|
||||
minute: "0"
|
||||
job: "docker compose -f /var/www/crm-ecosplay/docker-compose-prod.yml exec -T php php bin/console app:monitor:messenger --env=prod >> /var/log/crm-ecosplay-messenger.log 2>&1"
|
||||
user: bot
|
||||
|
||||
- name: Configure Meilisearch consistency check cron (daily at 3am)
|
||||
cron:
|
||||
name: "crm-ecosplay meilisearch consistency"
|
||||
minute: "0"
|
||||
hour: "3"
|
||||
job: "docker compose -f /var/www/crm-ecosplay/docker-compose-prod.yml exec -T php php bin/console app:meilisearch:check-consistency --fix --env=prod >> /var/log/crm-ecosplay-meilisearch.log 2>&1"
|
||||
user: bot
|
||||
|
||||
- name: Configure Stripe sync cron (every 6 hours)
|
||||
cron:
|
||||
name: "crm-ecosplay stripe sync"
|
||||
minute: "0"
|
||||
hour: "*/6"
|
||||
job: "docker compose -f /var/www/crm-ecosplay/docker-compose-prod.yml exec -T php php bin/console app:stripe:sync --env=prod >> /var/log/crm-ecosplay-stripe-sync.log 2>&1"
|
||||
user: bot
|
||||
|
||||
- name: Configure infra snapshot cron (every 5 minutes)
|
||||
cron:
|
||||
name: "crm-ecosplay infra snapshot"
|
||||
minute: "*/5"
|
||||
job: "docker compose -f /var/www/crm-ecosplay/docker-compose-prod.yml exec -T php php bin/console app:infra:snapshot --env=prod >> /var/log/crm-ecosplay-infra.log 2>&1"
|
||||
user: bot
|
||||
|
||||
- name: Configure attestations cleanup cron (daily at 4am)
|
||||
cron:
|
||||
name: "crm-ecosplay attestations clean"
|
||||
minute: "0"
|
||||
hour: "4"
|
||||
job: "docker compose -f /var/www/crm-ecosplay/docker-compose-prod.yml exec -T php php bin/console app:attestations:clean --env=prod >> /var/log/crm-ecosplay-attestations.log 2>&1"
|
||||
user: bot
|
||||
|
||||
- name: Configure services health check cron (every 15 minutes)
|
||||
cron:
|
||||
name: "crm-ecosplay services check"
|
||||
minute: "*/15"
|
||||
job: "docker compose -f /var/www/crm-ecosplay/docker-compose-prod.yml exec -T php php bin/console app:services:check --env=prod >> /var/log/crm-ecosplay-services.log 2>&1"
|
||||
user: bot
|
||||
|
||||
post_tasks:
|
||||
- name: Disable maintenance mode
|
||||
command: make maintenance_off
|
||||
args:
|
||||
chdir: /var/www/crm-ecosplay
|
||||
|
||||
handlers:
|
||||
- name: Reload Caddy
|
||||
systemd:
|
||||
name: caddy
|
||||
state: reloaded
|
||||
|
||||
211
ansible/docker-compose-prod.yml.j2
Normal file
211
ansible/docker-compose-prod.yml.j2
Normal file
@@ -0,0 +1,211 @@
|
||||
name: crm-ecosplay
|
||||
|
||||
services:
|
||||
php:
|
||||
build:
|
||||
context: ./docker/php/prod
|
||||
dockerfile: Dockerfile
|
||||
deploy:
|
||||
replicas: 2
|
||||
resources:
|
||||
limits:
|
||||
cpus: "1.5"
|
||||
memory: 1G
|
||||
reservations:
|
||||
cpus: "0.5"
|
||||
memory: 256M
|
||||
restart: unless-stopped
|
||||
group_add:
|
||||
- "{{ docker_gid }}"
|
||||
volumes:
|
||||
- .:/app
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
ports:
|
||||
- "4568-4569:9000"
|
||||
networks:
|
||||
- crm_ecosplay
|
||||
depends_on:
|
||||
pgbouncer:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
|
||||
db-master:
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: "2.0"
|
||||
memory: 4G
|
||||
reservations:
|
||||
cpus: "0.5"
|
||||
memory: 1G
|
||||
environment:
|
||||
POSTGRES_USER: crm-ecosplay
|
||||
POSTGRES_PASSWORD: {{ db_password }}
|
||||
POSTGRES_DB: crm-ecosplay
|
||||
command:
|
||||
- postgres
|
||||
- -c
|
||||
- wal_level=replica
|
||||
- -c
|
||||
- max_wal_senders=3
|
||||
- -c
|
||||
- wal_keep_size=64MB
|
||||
- -c
|
||||
- hot_standby=on
|
||||
- -c
|
||||
- shared_buffers=1GB
|
||||
- -c
|
||||
- effective_cache_size=3GB
|
||||
- -c
|
||||
- work_mem=16MB
|
||||
volumes:
|
||||
- db-master-data:/var/lib/postgresql/data
|
||||
- ./docker/pgsql/init-master.sh:/docker-entrypoint-initdb.d/init-master.sh
|
||||
networks:
|
||||
- crm_ecosplay
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U crm-ecosplay -d crm-ecosplay"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
db-slave:
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: "1.5"
|
||||
memory: 2G
|
||||
reservations:
|
||||
cpus: "0.25"
|
||||
memory: 512M
|
||||
environment:
|
||||
POSTGRES_USER: crm-ecosplay
|
||||
POSTGRES_PASSWORD: {{ db_password }}
|
||||
POSTGRES_DB: crm-ecosplay
|
||||
PGDATA: /var/lib/postgresql/data
|
||||
volumes:
|
||||
- db-slave-data:/var/lib/postgresql/data
|
||||
- ./docker/pgsql/init-slave.sh:/init-slave.sh
|
||||
entrypoint: ["/bin/bash", "/init-slave.sh"]
|
||||
command: ["postgres"]
|
||||
networks:
|
||||
- crm_ecosplay
|
||||
depends_on:
|
||||
db-master:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U crm-ecosplay -d crm-ecosplay"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
pgbouncer:
|
||||
image: edoburu/pgbouncer
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: "0.5"
|
||||
memory: 128M
|
||||
reservations:
|
||||
cpus: "0.1"
|
||||
memory: 32M
|
||||
volumes:
|
||||
- ./docker/pgsql/pgbouncer.ini:/etc/pgbouncer/pgbouncer.ini:ro
|
||||
- ./docker/pgsql/userlist.txt:/etc/pgbouncer/userlist.txt:ro
|
||||
networks:
|
||||
- crm_ecosplay
|
||||
depends_on:
|
||||
db-master:
|
||||
condition: service_healthy
|
||||
db-slave:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -p 6432 -U crm-ecosplay"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
messenger:
|
||||
build:
|
||||
context: ./docker/php/prod
|
||||
dockerfile: Dockerfile
|
||||
command: php bin/console messenger:consume async --time-limit=3600 --memory-limit=256M --limit=500 -vv
|
||||
deploy:
|
||||
replicas: 2
|
||||
resources:
|
||||
limits:
|
||||
cpus: "1.0"
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: "0.25"
|
||||
memory: 128M
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- .:/app
|
||||
networks:
|
||||
- crm_ecosplay
|
||||
depends_on:
|
||||
pgbouncer:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
meilisearch:
|
||||
condition: service_started
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: "1.0"
|
||||
memory: 1G
|
||||
reservations:
|
||||
cpus: "0.25"
|
||||
memory: 128M
|
||||
command: redis-server --requirepass {{ redis_password }} --maxmemory 768mb --maxmemory-policy allkeys-lru
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
networks:
|
||||
- crm_ecosplay
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "{{ redis_password }}", "ping"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:latest
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: "1.0"
|
||||
memory: 1G
|
||||
reservations:
|
||||
cpus: "0.25"
|
||||
memory: 256M
|
||||
environment:
|
||||
MEILI_MASTER_KEY: {{ meilisearch_master_key }}
|
||||
MEILI_ENV: production
|
||||
MEILI_NO_ANALYTICS: true
|
||||
volumes:
|
||||
- meilisearch-data:/meili_data
|
||||
networks:
|
||||
- crm_ecosplay
|
||||
|
||||
networks:
|
||||
crm_ecosplay:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
db-master-data:
|
||||
db-slave-data:
|
||||
redis-data:
|
||||
meilisearch-data:
|
||||
33
ansible/env.local.j2
Normal file
33
ansible/env.local.j2
Normal file
@@ -0,0 +1,33 @@
|
||||
APP_ENV=prod
|
||||
APP_SECRET={{ app_secret }}
|
||||
DATABASE_URL="postgresql://crm-ecosplay:{{ db_password }}@pgbouncer:6432/crm-ecosplay?serverVersion=16&charset=utf8"
|
||||
MESSENGER_TRANSPORT_DSN=redis://:{{ redis_password }}@redis:6379/messages
|
||||
SESSION_HANDLER_DSN=redis://:{{ redis_password }}@redis:6379/1
|
||||
REDIS_CACHE_DSN=redis://:{{ redis_password }}@redis:6379/2
|
||||
MAILER_DSN={{ mailer_dsn }}
|
||||
DEFAULT_URI=https://ticket.e-cosplay.fr
|
||||
VITE_LOAD=1
|
||||
REAL_MAIL=1
|
||||
OUTSIDE_URL=https://ticket.e-cosplay.fr
|
||||
STRIPE_PK={{ stripe_pk }}
|
||||
STRIPE_SK={{ stripe_sk }}
|
||||
STRIPE_WEBHOOK_SECRET={{ stripe_webhook_secret }}
|
||||
STRIPE_WEBHOOK_SECRET_CONNECT={{ stripe_webhook_secret_connect }}
|
||||
STRIPE_MODE=live
|
||||
SMIME_PASSPHRASE='{{ smime_passphrase }}'
|
||||
MEILISEARCH_URL=http://meilisearch:7700
|
||||
MEILISEARCH_API_KEY={{ meilisearch_api_key }}
|
||||
SONARQUBE_URL=https://sn.esy-web.dev
|
||||
SONARQUBE_BADGE_TOKEN={{ sonarqube_badge_token }}
|
||||
SONARQUBE_PROJECT_KEY=crm-ecosplay
|
||||
OAUTH_KEYCLOAK_CLIENT_ID=crm_ecosplay
|
||||
OAUTH_KEYCLOAK_CLIENT_SECRET=QiksEpHqDCHFPMM9CWb3RHfag31VJfIV
|
||||
OAUTH_KEYCLOAK_URL=https://auth.esy-web.dev
|
||||
OAUTH_KEYCLOAK_REALM=e-cosplay
|
||||
SECRET_ANALYTICS={{ analytics_secret }}
|
||||
KEYCLOAK_ADMIN_CLIENT_ID=crm-ecosplay-admin
|
||||
KEYCLOAK_ADMIN_CLIENT_SECRET={{ keycloak_admin_client_secret }}
|
||||
DOCUSEAL_URL=https://signature.esy-web.dev
|
||||
DOCUSEAL_API={{ docuseal_api }}
|
||||
DOCUSEAL_WEBHOOKS_SECRET_HEADER=X-Sign
|
||||
DOCUSEAL_WEBHOOKS_SECRET={{ docuseal_webhooks_secret }}
|
||||
5
ansible/hosts.ini
Normal file
5
ansible/hosts.ini
Normal file
@@ -0,0 +1,5 @@
|
||||
[production]
|
||||
127.0.0.1 ansible_user=bot ansible_become=yes ansible_become_method=sudo ansible_connection=local
|
||||
|
||||
[production:vars]
|
||||
deploy_path=/var/www/crm.ecosplay/
|
||||
12
ansible/messenger.j2
Normal file
12
ansible/messenger.j2
Normal file
@@ -0,0 +1,12 @@
|
||||
[program:crm-ecosplay-messenger]
|
||||
command=docker compose -f /var/www/crm-ecosplay/docker-compose-prod.yml exec php php bin/console messenger:consume async --time-limit=3600 --memory-limit=256M --limit=500
|
||||
directory=/var/www/crm-ecosplay
|
||||
user=bot
|
||||
numprocs=2
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startsecs=0
|
||||
startretries=10
|
||||
stdout_logfile=/var/log/supervisor/crm-ecosplay-messenger-%(process_num)02d.log
|
||||
stderr_logfile=/var/log/supervisor/crm-ecosplay-messenger-%(process_num)02d-error.log
|
||||
21
ansible/pgbouncer.ini.j2
Normal file
21
ansible/pgbouncer.ini.j2
Normal file
@@ -0,0 +1,21 @@
|
||||
[databases]
|
||||
crm-ecosplay = host=db-master port=5432 dbname=crm-ecosplay
|
||||
crm-ecosplay_readonly = host=db-slave port=5432 dbname=crm-ecosplay
|
||||
|
||||
[pgbouncer]
|
||||
listen_addr = 0.0.0.0
|
||||
listen_port = 6432
|
||||
auth_type = plain
|
||||
auth_file = /etc/pgbouncer/userlist.txt
|
||||
pool_mode = transaction
|
||||
max_client_conn = 200
|
||||
default_pool_size = 20
|
||||
min_pool_size = 5
|
||||
reserve_pool_size = 5
|
||||
reserve_pool_timeout = 3
|
||||
server_lifetime = 3600
|
||||
server_idle_timeout = 600
|
||||
log_connections = 0
|
||||
log_disconnections = 0
|
||||
admin_users = crm-ecosplay
|
||||
stats_users = crm-ecosplay
|
||||
1
ansible/userlist.txt.j2
Normal file
1
ansible/userlist.txt.j2
Normal file
@@ -0,0 +1 @@
|
||||
"crm-ecosplay" "{{ db_password }}"
|
||||
50
ansible/vault.yml
Normal file
50
ansible/vault.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
cloudflare_api_token: cfk_wXHshV0AmOoKbWE19CIPoWJBeUCtSDUXo2mgkGuNe99eeac8
|
||||
cloudflare_zone_id: f9e2a44aa512b455c99286d2ae845862
|
||||
app_secret: 533326ee6417086112c42b1fc1843ff1db82b881988f87442118178ea4469cc2
|
||||
mailer_dsn: ses+smtp://AKIAWTT2T22CWBRBBDYN:BBdgb6KxRQ8mNcpWFJsZCJxbSGNdgLhKFiITMErfBlQP@default?region=eu-west-3&timeout=120
|
||||
stripe_pk: pk_live_51SUA1rP4ub49xK2ThoRH8efqGYNi1hrcWMzrqmDtJpMv12cmTzLa8ncJLUKLbOQNZTkm1jgptLfwt4hxEGqkVsHB00AK3ieZNl
|
||||
stripe_sk: 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
|
||||
stripe_webhook_secret: whsec_ivqY8C05aJ9mho2N3opJLriO2AuxIqOi
|
||||
stripe_webhook_secret_connect: whsec_0sG9BPYDysxQst9W6FTp44GpwtO2F6WQ
|
||||
smime_passphrase: 'EVz5zNV8h4ndSLOCWO9JeaQnIertQm7k'
|
||||
meilisearch_api_key: b9b0994ee46d9826a4ac58306c171fdd00c03ac6f8ff6a68cdd8f9f977ab415a
|
||||
meilisearch_master_key: 9e6a86cb9e9b09cdabf30a81e43bdb18892ee0d0ab478a16c50749b8f2ed83e4
|
||||
db_password: 46eafec68e1e7bc8015790998a2e8ea8b5e31461479588b7
|
||||
redis_password: 51f7559d1d14a6cf422628537fa562a94481936228e9291d
|
||||
sonarqube_badge_token: sqb_dc1d0f73af1016295f49d1c56bf60e115e43bf48
|
||||
keycloak_admin_client_secret: QqYnQc6p9aio4sBJYKNhpPsdrvpUtt2z
|
||||
docuseal_api: pgAU116mCFmeF7WQSezHqxtZW8V1fgo31u5d2FXoaKe
|
||||
docuseal_webhooks_secret: CRM_COSLAY
|
||||
smime_private_key: |
|
||||
Bag Attributes
|
||||
localKeyID: 75 15 E3 C2 1D 7B 61 75 99 B9 22 D8 FD A4 19 AC 6B BE 1F 8F
|
||||
friendlyName: contact@e-cosplay.fr
|
||||
Key Attributes: <No Attributes>
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC60+PtobUKQsjH
|
||||
vrRizgwIfR06OkOqYosn17wurYUCZquhGfaRL5nf+qDcOF2liczRfXOsTxnEK0J0
|
||||
s38JF9zWXTkIms4yfyL9xKOCBEPkNSe03wIcaKQjNB1iuDqW6npUm/ke6VmIAj4q
|
||||
ig6wwiViqWxkzcE2824RFBI0H4rtkxDNhEXOk6ccVzxz/MwxAvmKHuJQG7LtbysI
|
||||
KIZcGbNjlm2YmIebVYU44kpI0ZMzfvKsfy9eWX3VyYubpL4Rwsc9I+Z2jsun+nEc
|
||||
4heHamNu8NrKHWQP802NZvRkMR7t39APYnGcEOBe6eagDkn9DQpZrkxfXYUcteBA
|
||||
5y3RVBxJAgMBAAECggEASCuXNlJL0blnv0WLgEmRO2w9cKNWRUkI8Wy0rKFqKrnH
|
||||
nhWd+orVWcEDB98cSdi4Dsrz9sGdtfpyEwvNzJDzxblAUXMfqUEUnswpz41fPpZM
|
||||
DuJA+gFwOoskuOBq/aZ5eBrCeu7wn4oiQqOPNjfhYkIJdc1H0Lbrs1w6BfmTXN9S
|
||||
ilSL4GMv7YpEBPt86wiReIbE0DIqaR9Vm1UupkJe7WMc9LrxW6OM4kD5xQTFdJLC
|
||||
n6QbbX+TE3q+d6TrckK8PeBm+gIX2+NdEuuz7gpZGSybfqN1wqbkziUsifi+7gQi
|
||||
pxwxhDmCQ08DHplcBdjg1ZldVhaAdHEqCyWZtIZQGwKBgQD9RNXOskPhGBP28oZz
|
||||
a7APhROKHcEtb9BRj3mwzwIMr3SzJjoBI4SfRR3QcU8jD2uCLNio/cSqjAJVyk2f
|
||||
Z9wDONnXy4aNrsze0Fx+0t1VqIOVocFDJJHndHCiq2HHorqArvHtZxkj/0xIUx+K
|
||||
nVltevm7qLSAtR/vWTM1c9Zp/wKBgQC816PZxNEpyg5mgO+3gn5yONsObh2ZyZ/v
|
||||
KPEmFBjl69AfAxKeaEZaj35RmzdnAFKlv9QzNdAM67+oOIThcaQ+diyNUQegaJwc
|
||||
amUZHWjQ7RAJNM7lQz85zn9s/MZVC8iNF7xlPWK8Y/ifMwk5e+pAQ79PVwxKiW8y
|
||||
doXv1uuptwKBgQCPfVJNGr5OZx/YhysZdWd4Q4MAez8ZCQJTUyA0xfN5UGajoQK3
|
||||
5nGa8sOjdq7JRFE6nUHa7HthzJT+GfHEYElMIgd5tTt0RhaYHiBpUfpIL4LtYYln
|
||||
Cu8G3Pd7kfGB83YKthMm14Rs2pVTXJTAKcmit0uJwFkTmoqPRlA29nwB7QKBgQCp
|
||||
iVtzxcwWnW1iPz13XfNRbpPTl66Bg89PMk2VZxOXT6cQQHz1tB39bbf1YclScqrA
|
||||
XcEPnK9E+l2dk+hQUesnnIaQ9H9JVsFYjXhoHMweTcZIzZ01nLLlnesumJ0ieyq4
|
||||
6OddaMf85C+wFWyhrAr5WRknDLpfLJWlE11ZnnUCbwKBgQCXOLstj7bEi8N3H8PV
|
||||
UQlkFKrAmmEE4i3Y3Qqa1DMbm2XJBzPQQJIrDlCeIWs0jk0upOY34W+deWH5gbvW
|
||||
a/6bpvSzbWqgFD5DnayVkb7CvgEg+CKdUoUumRSs38pet29c/pdKPUxhMq8voIEg
|
||||
HpnyJcapAiLw0hv4ql380onf0A==
|
||||
-----END PRIVATE KEY-----
|
||||
157
assets/app.js
157
assets/app.js
@@ -1,10 +1,149 @@
|
||||
import './stimulus_bootstrap.js';
|
||||
/*
|
||||
* Welcome to your app's main JavaScript file!
|
||||
*
|
||||
* This file will be included onto the page via the importmap() Twig function,
|
||||
* which should already be in your base.html.twig.
|
||||
*/
|
||||
import './styles/app.css';
|
||||
import "./app.scss"
|
||||
|
||||
console.log('This log comes from assets/app.js - welcome to AssetMapper! 🎉');
|
||||
// Membre / Super Admin : mutuellement exclusif
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const memberCheckbox = document.querySelector('input[value="gp_member"]');
|
||||
const adminCheckbox = document.querySelector('input[value="super_admin_asso"]');
|
||||
|
||||
if (memberCheckbox && adminCheckbox) {
|
||||
memberCheckbox.addEventListener('change', () => {
|
||||
if (memberCheckbox.checked) {
|
||||
document.querySelectorAll('input[name="groups[]"]').forEach(cb => {
|
||||
if (cb !== memberCheckbox) {
|
||||
cb.checked = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
adminCheckbox.addEventListener('change', () => {
|
||||
if (adminCheckbox.checked) {
|
||||
memberCheckbox.checked = false;
|
||||
document.querySelectorAll('input[name="groups[]"]').forEach(cb => {
|
||||
if (cb !== memberCheckbox) {
|
||||
cb.checked = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Stats period selector
|
||||
const periodSelect = document.getElementById('stats-period-select');
|
||||
const customRange = document.getElementById('stats-custom-range');
|
||||
if (periodSelect && customRange) {
|
||||
periodSelect.addEventListener('change', () => {
|
||||
customRange.classList.toggle('hidden', periodSelect.value !== 'custom');
|
||||
});
|
||||
}
|
||||
|
||||
// data-confirm
|
||||
document.querySelectorAll('form[data-confirm]').forEach(form => {
|
||||
form.addEventListener('submit', (e) => {
|
||||
if (!confirm(form.dataset.confirm)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Sidebar dropdown toggle
|
||||
document.querySelectorAll('.sidebar-dropdown-btn').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const menu = btn.nextElementSibling;
|
||||
const arrow = btn.querySelector('.sidebar-dropdown-arrow');
|
||||
menu?.classList.toggle('hidden');
|
||||
arrow?.classList.toggle('rotate-180');
|
||||
});
|
||||
});
|
||||
|
||||
// Mobile sidebar toggle
|
||||
const sidebarToggle = document.getElementById('admin-sidebar-toggle');
|
||||
const sidebar = document.getElementById('admin-sidebar');
|
||||
const overlay = document.getElementById('admin-overlay');
|
||||
|
||||
if (sidebarToggle && sidebar && overlay) {
|
||||
sidebarToggle.addEventListener('click', () => {
|
||||
sidebar.classList.toggle('open');
|
||||
});
|
||||
|
||||
overlay.addEventListener('click', () => {
|
||||
sidebar.classList.remove('open');
|
||||
});
|
||||
}
|
||||
|
||||
// Mobile menu toggle (public)
|
||||
const mobileMenuBtn = document.getElementById('mobile-menu-btn');
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
const menuIconOpen = document.getElementById('menu-icon-open');
|
||||
const menuIconClose = document.getElementById('menu-icon-close');
|
||||
|
||||
if (mobileMenuBtn && mobileMenu) {
|
||||
mobileMenuBtn.addEventListener('click', () => {
|
||||
mobileMenu.classList.toggle('hidden');
|
||||
menuIconOpen?.classList.toggle('hidden');
|
||||
menuIconClose?.classList.toggle('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
// Cookie banner
|
||||
const cookieBanner = document.getElementById('cookie-banner');
|
||||
const cookieAccept = document.getElementById('cookie-accept');
|
||||
const cookieRefuse = document.getElementById('cookie-refuse');
|
||||
|
||||
if (cookieBanner && !localStorage.getItem('cookie_consent')) {
|
||||
cookieBanner.classList.remove('hidden');
|
||||
}
|
||||
|
||||
cookieAccept?.addEventListener('click', () => {
|
||||
localStorage.setItem('cookie_consent', 'accepted');
|
||||
cookieBanner?.classList.add('hidden');
|
||||
});
|
||||
|
||||
cookieRefuse?.addEventListener('click', () => {
|
||||
localStorage.setItem('cookie_consent', 'refused');
|
||||
cookieBanner?.classList.add('hidden');
|
||||
});
|
||||
|
||||
// Search (customers & revendeurs)
|
||||
const setupSearch = (inputId, resultsId, searchUrl, linkPrefix) => {
|
||||
const input = document.getElementById(inputId);
|
||||
const results = document.getElementById(resultsId);
|
||||
if (!input || !results) return;
|
||||
|
||||
let debounce;
|
||||
input.addEventListener('input', () => {
|
||||
clearTimeout(debounce);
|
||||
const q = input.value.trim();
|
||||
if (q.length < 2) {
|
||||
results.classList.add('hidden');
|
||||
results.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
debounce = setTimeout(async () => {
|
||||
const resp = await fetch(`${searchUrl}?q=${encodeURIComponent(q)}`);
|
||||
const hits = await resp.json();
|
||||
if (hits.length === 0) {
|
||||
results.innerHTML = '<div class="px-4 py-3 text-xs text-gray-400">Aucun resultat.</div>';
|
||||
} else {
|
||||
results.innerHTML = hits.map(h =>
|
||||
`<a href="${linkPrefix}${h.id}" class="block px-4 py-2 hover:bg-gray-50 border-b border-gray-100 text-xs">
|
||||
<span class="font-bold">${h.fullName || h.raisonSociale || (h.firstName + ' ' + h.lastName)}</span>
|
||||
${h.email ? `<span class="text-gray-400 ml-2">${h.email}</span>` : ''}
|
||||
${h.codeRevendeur ? `<span class="ml-2 px-1 py-0.5 bg-gray-900 text-[#fabf04] text-[9px] font-bold">${h.codeRevendeur}</span>` : ''}
|
||||
</a>`
|
||||
).join('');
|
||||
}
|
||||
results.classList.remove('hidden');
|
||||
}, 300);
|
||||
});
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!results.contains(e.target) && e.target !== input) {
|
||||
results.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
setupSearch('search-customers', 'search-results', '/admin/clients/search', '/admin/clients/');
|
||||
setupSearch('search-revendeurs', 'search-results-revendeurs', '/admin/revendeurs/search', '/admin/revendeurs/');
|
||||
});
|
||||
|
||||
28
assets/app.scss
Normal file
28
assets/app.scss
Normal file
@@ -0,0 +1,28 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
.page-container {
|
||||
width: 90%;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem 0;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
width: 80%;
|
||||
padding: 3rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.heading-page {
|
||||
border-bottom: 4px solid #111827;
|
||||
display: inline-block;
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.admin-content .page-container {
|
||||
width: 95%;
|
||||
max-width: none;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"controllers": {
|
||||
"@symfony/ux-turbo": {
|
||||
"turbo-core": {
|
||||
"enabled": true,
|
||||
"fetch": "eager"
|
||||
},
|
||||
"mercure-turbo-stream": {
|
||||
"enabled": false,
|
||||
"fetch": "eager"
|
||||
}
|
||||
}
|
||||
},
|
||||
"entrypoints": []
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
const nameCheck = /^[-_a-zA-Z0-9]{4,22}$/;
|
||||
const tokenCheck = /^[-_/+a-zA-Z0-9]{24,}$/;
|
||||
|
||||
// Generate and double-submit a CSRF token in a form field and a cookie, as defined by Symfony's SameOriginCsrfTokenManager
|
||||
// Use `form.requestSubmit()` to ensure that the submit event is triggered. Using `form.submit()` will not trigger the event
|
||||
// and thus this event-listener will not be executed.
|
||||
document.addEventListener('submit', function (event) {
|
||||
generateCsrfToken(event.target);
|
||||
}, true);
|
||||
|
||||
// When @hotwired/turbo handles form submissions, send the CSRF token in a header in addition to a cookie
|
||||
// The `framework.csrf_protection.check_header` config option needs to be enabled for the header to be checked
|
||||
document.addEventListener('turbo:submit-start', function (event) {
|
||||
const h = generateCsrfHeaders(event.detail.formSubmission.formElement);
|
||||
Object.keys(h).map(function (k) {
|
||||
event.detail.formSubmission.fetchRequest.headers[k] = h[k];
|
||||
});
|
||||
});
|
||||
|
||||
// When @hotwired/turbo handles form submissions, remove the CSRF cookie once a form has been submitted
|
||||
document.addEventListener('turbo:submit-end', function (event) {
|
||||
removeCsrfToken(event.detail.formSubmission.formElement);
|
||||
});
|
||||
|
||||
export function generateCsrfToken (formElement) {
|
||||
const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');
|
||||
|
||||
if (!csrfField) {
|
||||
return;
|
||||
}
|
||||
|
||||
let csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value');
|
||||
let csrfToken = csrfField.value;
|
||||
|
||||
if (!csrfCookie && nameCheck.test(csrfToken)) {
|
||||
csrfField.setAttribute('data-csrf-protection-cookie-value', csrfCookie = csrfToken);
|
||||
csrfField.defaultValue = csrfToken = btoa(String.fromCharCode.apply(null, (window.crypto || window.msCrypto).getRandomValues(new Uint8Array(18))));
|
||||
}
|
||||
csrfField.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
|
||||
if (csrfCookie && tokenCheck.test(csrfToken)) {
|
||||
const cookie = csrfCookie + '_' + csrfToken + '=' + csrfCookie + '; path=/; samesite=strict';
|
||||
document.cookie = window.location.protocol === 'https:' ? '__Host-' + cookie + '; secure' : cookie;
|
||||
}
|
||||
}
|
||||
|
||||
export function generateCsrfHeaders (formElement) {
|
||||
const headers = {};
|
||||
const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');
|
||||
|
||||
if (!csrfField) {
|
||||
return headers;
|
||||
}
|
||||
|
||||
const csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value');
|
||||
|
||||
if (tokenCheck.test(csrfField.value) && nameCheck.test(csrfCookie)) {
|
||||
headers[csrfCookie] = csrfField.value;
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
export function removeCsrfToken (formElement) {
|
||||
const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');
|
||||
|
||||
if (!csrfField) {
|
||||
return;
|
||||
}
|
||||
|
||||
const csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value');
|
||||
|
||||
if (tokenCheck.test(csrfField.value) && nameCheck.test(csrfCookie)) {
|
||||
const cookie = csrfCookie + '_' + csrfField.value + '=0; path=/; samesite=strict; max-age=0';
|
||||
|
||||
document.cookie = window.location.protocol === 'https:' ? '__Host-' + cookie + '; secure' : cookie;
|
||||
}
|
||||
}
|
||||
|
||||
/* stimulusFetch: 'lazy' */
|
||||
export default 'csrf-protection-controller';
|
||||
@@ -1,16 +0,0 @@
|
||||
import { Controller } from '@hotwired/stimulus';
|
||||
|
||||
/*
|
||||
* This is an example Stimulus controller!
|
||||
*
|
||||
* Any element with a data-controller="hello" attribute will cause
|
||||
* this controller to be executed. The name "hello" comes from the filename:
|
||||
* hello_controller.js -> "hello"
|
||||
*
|
||||
* Delete this file or adapt it for your use!
|
||||
*/
|
||||
export default class extends Controller {
|
||||
connect() {
|
||||
this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js';
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { startStimulusApp } from '@symfony/stimulus-bundle';
|
||||
|
||||
const app = startStimulusApp();
|
||||
// register any custom, 3rd party controllers here
|
||||
// app.register('some_controller_name', SomeImportedController);
|
||||
@@ -1,3 +0,0 @@
|
||||
body {
|
||||
background-color: skyblue;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
|
||||
services:
|
||||
###> doctrine/doctrine-bundle ###
|
||||
database:
|
||||
ports:
|
||||
- "5432"
|
||||
###< doctrine/doctrine-bundle ###
|
||||
|
||||
###> symfony/mailer ###
|
||||
mailer:
|
||||
image: axllent/mailpit
|
||||
ports:
|
||||
- "1025"
|
||||
- "8025"
|
||||
environment:
|
||||
MP_SMTP_AUTH_ACCEPT_ANY: 1
|
||||
MP_SMTP_AUTH_ALLOW_INSECURE: 1
|
||||
###< symfony/mailer ###
|
||||
25
compose.yaml
25
compose.yaml
@@ -1,25 +0,0 @@
|
||||
|
||||
services:
|
||||
###> doctrine/doctrine-bundle ###
|
||||
database:
|
||||
image: postgres:${POSTGRES_VERSION:-16}-alpine
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB:-app}
|
||||
# You should definitely change the password in production
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!}
|
||||
POSTGRES_USER: ${POSTGRES_USER:-app}
|
||||
healthcheck:
|
||||
test: ["CMD", "pg_isready", "-d", "${POSTGRES_DB:-app}", "-U", "${POSTGRES_USER:-app}"]
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 60s
|
||||
volumes:
|
||||
- database_data:/var/lib/postgresql/data:rw
|
||||
# You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data!
|
||||
# - ./docker/db/data:/var/lib/postgresql/data:rw
|
||||
###< doctrine/doctrine-bundle ###
|
||||
|
||||
volumes:
|
||||
###> doctrine/doctrine-bundle ###
|
||||
database_data:
|
||||
###< doctrine/doctrine-bundle ###
|
||||
@@ -7,48 +7,69 @@
|
||||
"php": ">=8.4",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"doctrine/doctrine-bundle": "^3.2",
|
||||
"doctrine/doctrine-bundle": "^3.2.2",
|
||||
"doctrine/doctrine-migrations-bundle": "^4.0",
|
||||
"doctrine/orm": "^3.6",
|
||||
"phpdocumentor/reflection-docblock": "^6.0",
|
||||
"phpstan/phpdoc-parser": "^2.3",
|
||||
"doctrine/orm": "^3.6.2",
|
||||
"docusealco/docuseal-php": "^1.0",
|
||||
"dompdf/dompdf": ">=3.1.5",
|
||||
"endroid/qr-code-bundle": ">=6.1",
|
||||
"knplabs/knp-paginator-bundle": "^6.10",
|
||||
"knpuniversity/oauth2-client-bundle": "^2.20.2",
|
||||
"league/flysystem-bundle": "^3.6.2",
|
||||
"liip/imagine-bundle": "^2.17.1",
|
||||
"meilisearch/meilisearch-php": "^1.16",
|
||||
"mobiledetect/mobiledetectlib": ">=4.8.10",
|
||||
"nelmio/security-bundle": "^3.9",
|
||||
"phpdocumentor/reflection-docblock": "^6.0.3",
|
||||
"phpstan/phpdoc-parser": "^2.3.2",
|
||||
"scheb/2fa-backup-code": "^8.5",
|
||||
"scheb/2fa-bundle": "^8.5",
|
||||
"scheb/2fa-email": "^8.5",
|
||||
"scheb/2fa-google-authenticator": "^8.5",
|
||||
"spomky-labs/pwa-bundle": "1.5.7",
|
||||
"stevenmaguire/oauth2-keycloak": "^6.1.1",
|
||||
"stripe/stripe-php": ">=20",
|
||||
"symfony/amazon-mailer": "8.0.*",
|
||||
"symfony/asset": "8.0.*",
|
||||
"symfony/asset-mapper": "8.0.*",
|
||||
"symfony/console": "8.0.*",
|
||||
"symfony/doctrine-messenger": "8.0.*",
|
||||
"symfony/dotenv": "8.0.*",
|
||||
"symfony/expression-language": "8.0.*",
|
||||
"symfony/flex": "^2",
|
||||
"symfony/flex": "^2.10",
|
||||
"symfony/form": "8.0.*",
|
||||
"symfony/framework-bundle": "8.0.*",
|
||||
"symfony/http-client": "8.0.*",
|
||||
"symfony/intl": "8.0.*",
|
||||
"symfony/mailer": "8.0.*",
|
||||
"symfony/mime": "8.0.*",
|
||||
"symfony/monolog-bundle": "^3.0|^4.0",
|
||||
"symfony/monolog-bundle": "^3.0|^4.0.1",
|
||||
"symfony/notifier": "8.0.*",
|
||||
"symfony/process": "8.0.*",
|
||||
"symfony/property-access": "8.0.*",
|
||||
"symfony/property-info": "8.0.*",
|
||||
"symfony/rate-limiter": "8.0.*",
|
||||
"symfony/redis-messenger": "8.0.*",
|
||||
"symfony/runtime": "8.0.*",
|
||||
"symfony/security-bundle": "8.0.*",
|
||||
"symfony/serializer": "8.0.*",
|
||||
"symfony/stimulus-bundle": "^2.34",
|
||||
"symfony/string": "8.0.*",
|
||||
"symfony/translation": "8.0.*",
|
||||
"symfony/twig-bundle": "8.0.*",
|
||||
"symfony/ux-turbo": "^2.34",
|
||||
"symfony/validator": "8.0.*",
|
||||
"symfony/web-link": "8.0.*",
|
||||
"symfony/yaml": "8.0.*",
|
||||
"twig/extra-bundle": "^2.12|^3.0",
|
||||
"twig/twig": "^2.12|^3.0"
|
||||
"twig/cssinliner-extra": "^3.24",
|
||||
"twig/extra-bundle": "^2.12|^3.24",
|
||||
"twig/inky-extra": "^3.24",
|
||||
"twig/twig": "^2.12|^3.24",
|
||||
"vich/uploader-bundle": "^2.9.2"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"php-http/discovery": true,
|
||||
"symfony/flex": true,
|
||||
"symfony/runtime": true
|
||||
"symfony/runtime": true,
|
||||
"endroid/installer": true
|
||||
},
|
||||
"bump-after-update": true,
|
||||
"sort-packages": true
|
||||
@@ -98,11 +119,13 @@
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^13.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.94.2",
|
||||
"phpstan/phpstan": "^2.1.45",
|
||||
"phpunit/phpunit": "^13.0.5",
|
||||
"symfony/browser-kit": "8.0.*",
|
||||
"symfony/css-selector": "8.0.*",
|
||||
"symfony/debug-bundle": "8.0.*",
|
||||
"symfony/maker-bundle": "^1.0",
|
||||
"symfony/maker-bundle": "^1.67",
|
||||
"symfony/stopwatch": "8.0.*",
|
||||
"symfony/web-profiler-bundle": "8.0.*"
|
||||
}
|
||||
|
||||
9615
composer.lock
generated
9615
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -7,10 +7,17 @@ return [
|
||||
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
|
||||
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
||||
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
||||
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
|
||||
Symfony\UX\Turbo\TurboBundle::class => ['all' => true],
|
||||
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
|
||||
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||
Endroid\QrCodeBundle\EndroidQrCodeBundle::class => ['all' => true],
|
||||
Knp\Bundle\PaginatorBundle\KnpPaginatorBundle::class => ['all' => true],
|
||||
KnpU\OAuth2ClientBundle\KnpUOAuth2ClientBundle::class => ['all' => true],
|
||||
League\FlysystemBundle\FlysystemBundle::class => ['all' => true],
|
||||
Liip\ImagineBundle\LiipImagineBundle::class => ['all' => true],
|
||||
Nelmio\SecurityBundle\NelmioSecurityBundle::class => ['all' => true],
|
||||
SpomkyLabs\PwaBundle\SpomkyLabsPwaBundle::class => ['all' => true],
|
||||
Vich\UploaderBundle\VichUploaderBundle::class => ['all' => true],
|
||||
Scheb\TwoFactorBundle\SchebTwoFactorBundle::class => ['all' => true],
|
||||
];
|
||||
|
||||
125
config/cert/smime/certificate.pem
Normal file
125
config/cert/smime/certificate.pem
Normal file
@@ -0,0 +1,125 @@
|
||||
Bag Attributes
|
||||
localKeyID: 75 15 E3 C2 1D 7B 61 75 99 B9 22 D8 FD A4 19 AC 6B BE 1F 8F
|
||||
friendlyName: contact@e-cosplay.fr
|
||||
subject=CN = contact@e-cosplay.fr
|
||||
issuer=C = IT, ST = Bergamo, L = Ponte San Pietro, O = Actalis S.p.A., CN = Actalis Client Authentication CA G3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF7TCCA9WgAwIBAgIQVGwKj9U0zzzn3LBvYN7iODANBgkqhkiG9w0BAQsFADCB
|
||||
gTELMAkGA1UEBhMCSVQxEDAOBgNVBAgMB0JlcmdhbW8xGTAXBgNVBAcMEFBvbnRl
|
||||
IFNhbiBQaWV0cm8xFzAVBgNVBAoMDkFjdGFsaXMgUy5wLkEuMSwwKgYDVQQDDCNB
|
||||
Y3RhbGlzIENsaWVudCBBdXRoZW50aWNhdGlvbiBDQSBHMzAeFw0yNjAyMDEwOTM4
|
||||
NTdaFw0yNzAyMDEwOTM4NTdaMB8xHTAbBgNVBAMMFGNvbnRhY3RAZS1jb3NwbGF5
|
||||
LmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAutPj7aG1CkLIx760
|
||||
Ys4MCH0dOjpDqmKLJ9e8Lq2FAmaroRn2kS+Z3/qg3DhdpYnM0X1zrE8ZxCtCdLN/
|
||||
CRfc1l05CJrOMn8i/cSjggRD5DUntN8CHGikIzQdYrg6lup6VJv5HulZiAI+KooO
|
||||
sMIlYqlsZM3BNvNuERQSNB+K7ZMQzYRFzpOnHFc8c/zMMQL5ih7iUBuy7W8rCCiG
|
||||
XBmzY5ZtmJiHm1WFOOJKSNGTM37yrH8vXll91cmLm6S+EcLHPSPmdo7Lp/pxHOIX
|
||||
h2pjbvDayh1kD/NNjWb0ZDEe7d/QD2JxnBDgXunmoA5J/Q0KWa5MX12FHLXgQOct
|
||||
0VQcSQIDAQABo4IBwDCCAbwwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBS+l6mq
|
||||
hL+AvxBTfQky+eEuMhvPdzB+BggrBgEFBQcBAQRyMHAwOwYIKwYBBQUHMAKGL2h0
|
||||
dHA6Ly9jYWNlcnQuYWN0YWxpcy5pdC9jZXJ0cy9hY3RhbGlzLWF1dGNsaWczMDEG
|
||||
CCsGAQUFBzABhiVodHRwOi8vb2NzcDA5LmFjdGFsaXMuaXQvVkEvQVVUSENMLUcz
|
||||
MB8GA1UdEQQYMBaBFGNvbnRhY3RAZS1jb3NwbGF5LmZyMFIGA1UdIARLMEkwPAYG
|
||||
K4EfEAEBMDIwMAYIKwYBBQUHAgEWJGh0dHBzOi8vd3d3LmFjdGFsaXMuaXQvYXJl
|
||||
YS1kb3dubG9hZDAJBgdngQwBBQECMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
|
||||
BQcDBDBIBgNVHR8EQTA/MD2gO6A5hjdodHRwOi8vY3JsMDkuYWN0YWxpcy5pdC9S
|
||||
ZXBvc2l0b3J5L0FVVEhDTC1HMy9nZXRMYXN0Q1JMMB0GA1UdDgQWBBR1FePCHXth
|
||||
dZm5Itj9pBmsa74fjzAOBgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQELBQADggIB
|
||||
AHU6pUBlyDdhCM4pya79GlvPDn64JL9WzWHZnKbMBFQBwmXCuvKZYK5c3aMhw7QV
|
||||
+XIMPvEdzkhFkhBf4/t6ZGE3LZjn1G+pDWA+6rWe/yhhZKgtbR6ll02K0RUi9d5A
|
||||
GukCOpSEaOMDE7Mn0inG+Rozx28PR/0qRVTCoBN7aCH7Z08BSigwIXsoXo6aglrv
|
||||
9OI6IYRC4/x2oOA25g6ONl8I10mba17QLKY0OLaPYA23+wK6cd5XaQ+Xbl7anOAC
|
||||
gWv3ZkGzLq/54jqhDfmu42HnwDD8PC+uXR/4JGFtQncAu9PYua8BW7STnAv2dY9E
|
||||
j3p8BFzUH6LDijMRZxexZR97X+WHkA2Pei7eMEKmF5EpTRm7/q9LZLBiwa2aqfdf
|
||||
5Cwjeq/pM96JHTj2wlA84e2EF+5yqslRKQ//lLtXLnch6oVi4hrhvCnFqkMnJt66
|
||||
Doxwm0U0X3o4TdHgPGhFwnxXWEstlOvhAK3fCkY2/ZKk9PUFnc4nsOr1c7ckgLKO
|
||||
ks76UBmXPQnrsj66ahwiXaQDMPk14/ponWjPdpy6cvE0zIcA8G+zGJLXh/fRro9P
|
||||
Bo+2YpoM9fA7W4vt3NwJyG+GdALEa0TNBNimppe1usdIFJ3yrdAaa8gJJ49qmGvE
|
||||
0mxpxuXxY7nMiI5G+H4h1rx5r2VlyRJrpxBmC+zgtvMD
|
||||
-----END CERTIFICATE-----
|
||||
Bag Attributes
|
||||
2.16.840.1.113894.746875.1.1: <Unsupported tag 6>
|
||||
<Unsupported tag 6>
|
||||
friendlyName: Actalis Client Authentication CA G3
|
||||
subject=C = IT, ST = Bergamo, L = Ponte San Pietro, O = Actalis S.p.A., CN = Actalis Client Authentication CA G3
|
||||
issuer=C = IT, L = Milan, O = Actalis S.p.A./03358520967, CN = Actalis Authentication Root CA
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIHbTCCBVWgAwIBAgIQFxA+3j2KHLXKBlGT58pDazANBgkqhkiG9w0BAQsFADBr
|
||||
MQswCQYDVQQGEwJJVDEOMAwGA1UEBwwFTWlsYW4xIzAhBgNVBAoMGkFjdGFsaXMg
|
||||
Uy5wLkEuLzAzMzU4NTIwOTY3MScwJQYDVQQDDB5BY3RhbGlzIEF1dGhlbnRpY2F0
|
||||
aW9uIFJvb3QgQ0EwHhcNMjAwNzA2MDg0NTQ3WhcNMzAwOTIyMTEyMjAyWjCBgTEL
|
||||
MAkGA1UEBhMCSVQxEDAOBgNVBAgMB0JlcmdhbW8xGTAXBgNVBAcMEFBvbnRlIFNh
|
||||
biBQaWV0cm8xFzAVBgNVBAoMDkFjdGFsaXMgUy5wLkEuMSwwKgYDVQQDDCNBY3Rh
|
||||
bGlzIENsaWVudCBBdXRoZW50aWNhdGlvbiBDQSBHMzCCAiIwDQYJKoZIhvcNAQEB
|
||||
BQADggIPADCCAgoCggIBAO3mh5ahwaS27cJCVfc/Dw8iYF8T4KZDiIZJkXkcGy8a
|
||||
UA/cRgHu9ro6hsxRYe/ED4AIcSlarRh82HqtFSVQs4ZwikQW1V/icCIS91C2IVAG
|
||||
a1YlKfedqgweqky+bBniUvRevVT0keZOqRTcO5hw007dL6FhYNmlZBt5IaJs1V6I
|
||||
niRjokOHR++qWgrUGy5LefY6ACs9gZ8Bi0OMK9PZ37pibeQCsdmMRytl4Ej7JVWe
|
||||
M/BtNIIprHwO1LY0/8InpGOmdG+5LC6xHLzg53B0HvVUqzUQNePUhNwJZFmmTP46
|
||||
FXovxmH4/SuY5IkXop0eJqjN+dxRHHizngYUk1EaTHUOcLFy4vQ0kxgbjb+GsNg6
|
||||
M2/6gZZIRk78JPdpotIwHnBNtkp9wPVH61NqdcP7kbPkyLXkNMTtAfydpmNnGqqH
|
||||
LEvUrK4iBpUPG9C09KOjm9OyhrT2uf5SLzJsee9g79r/rw4hAgcsZtR3YI6fCbRO
|
||||
JncmD+hgbHCck+9TWcNc1x5xZMgm8UXmoPamkkfceAlVV49QQ5jUTgqneTQHyF1F
|
||||
2ExXmf47pEIoJMVxloRIXywQuB2uqcIs8/X6tfsMDynFmhfT/0mTrgQ6xt9DIsgm
|
||||
WuuhvZhLReWS7oeKxnyqscuGeTMXnLs7fjGZq0inyhnlznhA/4rl+WdNjNaO4jEv
|
||||
AgMBAAGjggH0MIIB8DAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFFLYiDrI
|
||||
n3hm7YnzezhwlMkCAjbQMEEGCCsGAQUFBwEBBDUwMzAxBggrBgEFBQcwAYYlaHR0
|
||||
cDovL29jc3AwNS5hY3RhbGlzLml0L1ZBL0FVVEgtUk9PVDBFBgNVHSAEPjA8MDoG
|
||||
BFUdIAAwMjAwBggrBgEFBQcCARYkaHR0cHM6Ly93d3cuYWN0YWxpcy5pdC9hcmVh
|
||||
LWRvd25sb2FkMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDCB4wYDVR0f
|
||||
BIHbMIHYMIGWoIGToIGQhoGNbGRhcDovL2xkYXAwNS5hY3RhbGlzLml0L2NuJTNk
|
||||
QWN0YWxpcyUyMEF1dGhlbnRpY2F0aW9uJTIwUm9vdCUyMENBLG8lM2RBY3RhbGlz
|
||||
JTIwUy5wLkEuJTJmMDMzNTg1MjA5NjcsYyUzZElUP2NlcnRpZmljYXRlUmV2b2Nh
|
||||
dGlvbkxpc3Q7YmluYXJ5MD2gO6A5hjdodHRwOi8vY3JsMDUuYWN0YWxpcy5pdC9S
|
||||
ZXBvc2l0b3J5L0FVVEgtUk9PVC9nZXRMYXN0Q1JMMB0GA1UdDgQWBBS+l6mqhL+A
|
||||
vxBTfQky+eEuMhvPdzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIB
|
||||
ACab5xtZDXSzEgPp51X3hICFzULDO2EcV8em5hLfSCKxZR9amCnjcODVfMbaKfdU
|
||||
ZXtevMIIZmHgkz9dBan7ijGbJXjZCPP29zwZGSyCjpfadg5s9hnNCN1r3DGwIHfy
|
||||
LgbcfffDyV/2wW+XTGbhldnazZsX892q+srRmC8XnX4ygg+eWL/AkHDenvbFuTlJ
|
||||
vUyd5I7e1nb3dYXMObPu24ZTQ9/K1hSQbs7pqecaptTUjoIDpBUpSp4Us+h1I4MA
|
||||
WonemKYoPS9f0y65JrRCKcfsKSI+1kwPSanDDMiydKzeo46XrS0hlA5NzQjqUJ7U
|
||||
suGvPtDvknqc0v03nNXBnUjejYtvwO3sEDXdUW5m9kjNqlQZXzdHumZJVqPUGKTW
|
||||
cn9Hf3d7qbCmmxPXjQoNUuHg56fLCanZWkEO4SP1GAgIA7SyJu/yffv0ts7sBFrS
|
||||
TD3L2mCAXM3Y8BfblvvDSf2bvySm/fPe9brmuzrCXsTxUQc1+/z5ydvzV3E3cLnU
|
||||
oSXP6XfXNyEVO6sPkcUSnISHM798xLkCTB5EkjPCjPE2zs4v9L9JVOkkskvW6RnW
|
||||
WccdfR3fELNHL/kep8re6IbbYs8Hn5GM0Ohs8CMDPYEox+QX/6/SnOfyaqqSilBo
|
||||
nMQBstsymBBgdEKO+tTHHCMnJQVvZn7jRQ20wXgxMrvN
|
||||
-----END CERTIFICATE-----
|
||||
Bag Attributes
|
||||
2.16.840.1.113894.746875.1.1: <Unsupported tag 6>
|
||||
friendlyName: Actalis Authentication Root CA
|
||||
subject=C = IT, L = Milan, O = Actalis S.p.A./03358520967, CN = Actalis Authentication Root CA
|
||||
issuer=C = IT, L = Milan, O = Actalis S.p.A./03358520967, CN = Actalis Authentication Root CA
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE
|
||||
BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w
|
||||
MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
|
||||
IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC
|
||||
SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1
|
||||
ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv
|
||||
UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX
|
||||
4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9
|
||||
KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/
|
||||
gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb
|
||||
rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ
|
||||
51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F
|
||||
be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe
|
||||
KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F
|
||||
v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn
|
||||
fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7
|
||||
jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz
|
||||
ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
|
||||
ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL
|
||||
e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70
|
||||
jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz
|
||||
WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V
|
||||
SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j
|
||||
pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX
|
||||
X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok
|
||||
fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R
|
||||
K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU
|
||||
ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU
|
||||
LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
|
||||
LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
|
||||
-----END CERTIFICATE-----
|
||||
BIN
config/cert/smime/email_cer.p12
Normal file
BIN
config/cert/smime/email_cer.p12
Normal file
Binary file not shown.
32
config/cert/smime/private-key.pem
Normal file
32
config/cert/smime/private-key.pem
Normal file
@@ -0,0 +1,32 @@
|
||||
Bag Attributes
|
||||
localKeyID: 75 15 E3 C2 1D 7B 61 75 99 B9 22 D8 FD A4 19 AC 6B BE 1F 8F
|
||||
friendlyName: contact@e-cosplay.fr
|
||||
Key Attributes: <No Attributes>
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC60+PtobUKQsjH
|
||||
vrRizgwIfR06OkOqYosn17wurYUCZquhGfaRL5nf+qDcOF2liczRfXOsTxnEK0J0
|
||||
s38JF9zWXTkIms4yfyL9xKOCBEPkNSe03wIcaKQjNB1iuDqW6npUm/ke6VmIAj4q
|
||||
ig6wwiViqWxkzcE2824RFBI0H4rtkxDNhEXOk6ccVzxz/MwxAvmKHuJQG7LtbysI
|
||||
KIZcGbNjlm2YmIebVYU44kpI0ZMzfvKsfy9eWX3VyYubpL4Rwsc9I+Z2jsun+nEc
|
||||
4heHamNu8NrKHWQP802NZvRkMR7t39APYnGcEOBe6eagDkn9DQpZrkxfXYUcteBA
|
||||
5y3RVBxJAgMBAAECggEASCuXNlJL0blnv0WLgEmRO2w9cKNWRUkI8Wy0rKFqKrnH
|
||||
nhWd+orVWcEDB98cSdi4Dsrz9sGdtfpyEwvNzJDzxblAUXMfqUEUnswpz41fPpZM
|
||||
DuJA+gFwOoskuOBq/aZ5eBrCeu7wn4oiQqOPNjfhYkIJdc1H0Lbrs1w6BfmTXN9S
|
||||
ilSL4GMv7YpEBPt86wiReIbE0DIqaR9Vm1UupkJe7WMc9LrxW6OM4kD5xQTFdJLC
|
||||
n6QbbX+TE3q+d6TrckK8PeBm+gIX2+NdEuuz7gpZGSybfqN1wqbkziUsifi+7gQi
|
||||
pxwxhDmCQ08DHplcBdjg1ZldVhaAdHEqCyWZtIZQGwKBgQD9RNXOskPhGBP28oZz
|
||||
a7APhROKHcEtb9BRj3mwzwIMr3SzJjoBI4SfRR3QcU8jD2uCLNio/cSqjAJVyk2f
|
||||
Z9wDONnXy4aNrsze0Fx+0t1VqIOVocFDJJHndHCiq2HHorqArvHtZxkj/0xIUx+K
|
||||
nVltevm7qLSAtR/vWTM1c9Zp/wKBgQC816PZxNEpyg5mgO+3gn5yONsObh2ZyZ/v
|
||||
KPEmFBjl69AfAxKeaEZaj35RmzdnAFKlv9QzNdAM67+oOIThcaQ+diyNUQegaJwc
|
||||
amUZHWjQ7RAJNM7lQz85zn9s/MZVC8iNF7xlPWK8Y/ifMwk5e+pAQ79PVwxKiW8y
|
||||
doXv1uuptwKBgQCPfVJNGr5OZx/YhysZdWd4Q4MAez8ZCQJTUyA0xfN5UGajoQK3
|
||||
5nGa8sOjdq7JRFE6nUHa7HthzJT+GfHEYElMIgd5tTt0RhaYHiBpUfpIL4LtYYln
|
||||
Cu8G3Pd7kfGB83YKthMm14Rs2pVTXJTAKcmit0uJwFkTmoqPRlA29nwB7QKBgQCp
|
||||
iVtzxcwWnW1iPz13XfNRbpPTl66Bg89PMk2VZxOXT6cQQHz1tB39bbf1YclScqrA
|
||||
XcEPnK9E+l2dk+hQUesnnIaQ9H9JVsFYjXhoHMweTcZIzZ01nLLlnesumJ0ieyq4
|
||||
6OddaMf85C+wFWyhrAr5WRknDLpfLJWlE11ZnnUCbwKBgQCXOLstj7bEi8N3H8PV
|
||||
UQlkFKrAmmEE4i3Y3Qqa1DMbm2XJBzPQQJIrDlCeIWs0jk0upOY34W+deWH5gbvW
|
||||
a/6bpvSzbWqgFD5DnayVkb7CvgEg+CKdUoUumRSs38pet29c/pdKPUxhMq8voIEg
|
||||
HpnyJcapAiLw0hv4ql380onf0A==
|
||||
-----END PRIVATE KEY-----
|
||||
10
config/packages/dev/nelmio_security.yaml
Normal file
10
config/packages/dev/nelmio_security.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
nelmio_security:
|
||||
csp:
|
||||
enforce:
|
||||
script-src:
|
||||
- 'wasm-unsafe-eval'
|
||||
- 'http://localhost:5173/'
|
||||
style-src:
|
||||
- 'unsafe-inline'
|
||||
connect-src:
|
||||
- 'ws://localhost:5173'
|
||||
7
config/packages/flysystem.yaml
Normal file
7
config/packages/flysystem.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
# Read the documentation at https://github.com/thephpleague/flysystem-bundle/blob/master/docs/1-getting-started.md
|
||||
flysystem:
|
||||
storages:
|
||||
default.storage:
|
||||
adapter: 'local'
|
||||
options:
|
||||
directory: '%kernel.project_dir%/var/storage/default'
|
||||
@@ -1,6 +1,8 @@
|
||||
# see https://symfony.com/doc/current/reference/configuration/framework.html
|
||||
framework:
|
||||
secret: '%env(APP_SECRET)%'
|
||||
trusted_proxies: 'REMOTE_ADDR'
|
||||
trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port']
|
||||
|
||||
# Note that the session will be started ONLY if you read or write from it.
|
||||
session: true
|
||||
|
||||
10
config/packages/http_discovery.yaml
Normal file
10
config/packages/http_discovery.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
services:
|
||||
Psr\Http\Message\RequestFactoryInterface: '@http_discovery.psr17_factory'
|
||||
Psr\Http\Message\ResponseFactoryInterface: '@http_discovery.psr17_factory'
|
||||
Psr\Http\Message\ServerRequestFactoryInterface: '@http_discovery.psr17_factory'
|
||||
Psr\Http\Message\StreamFactoryInterface: '@http_discovery.psr17_factory'
|
||||
Psr\Http\Message\UploadedFileFactoryInterface: '@http_discovery.psr17_factory'
|
||||
Psr\Http\Message\UriFactoryInterface: '@http_discovery.psr17_factory'
|
||||
|
||||
http_discovery.psr17_factory:
|
||||
class: Http\Discovery\Psr17Factory
|
||||
9
config/packages/knpu_oauth2_client.yaml
Normal file
9
config/packages/knpu_oauth2_client.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
knpu_oauth2_client:
|
||||
clients:
|
||||
keycloak:
|
||||
type: keycloak
|
||||
auth_server_url: '%env(OAUTH_KEYCLOAK_URL)%'
|
||||
realm: '%env(OAUTH_KEYCLOAK_REALM)%'
|
||||
client_id: '%env(OAUTH_KEYCLOAK_CLIENT_ID)%'
|
||||
client_secret: '%env(OAUTH_KEYCLOAK_CLIENT_SECRET)%'
|
||||
redirect_route: connect_keycloak_check
|
||||
49
config/packages/liip_imagine.yaml
Normal file
49
config/packages/liip_imagine.yaml
Normal file
@@ -0,0 +1,49 @@
|
||||
liip_imagine:
|
||||
driver: "imagick"
|
||||
twig:
|
||||
mode: lazy
|
||||
webp:
|
||||
generate: true
|
||||
quality: 85
|
||||
filter_sets:
|
||||
webp:
|
||||
quality: 85
|
||||
format: 'webp'
|
||||
filters:
|
||||
strip: ~
|
||||
avatar_partner:
|
||||
quality: 75
|
||||
format: 'webp'
|
||||
filters:
|
||||
strip: ~
|
||||
thumbnail: { size: [ 128, 128 ], mode: inset }
|
||||
members:
|
||||
quality: 75
|
||||
format: 'webp'
|
||||
filters:
|
||||
strip: ~
|
||||
thumbnail: { size: [ 128, 128 ], mode: inset }
|
||||
navbar_logo:
|
||||
quality: 85
|
||||
format: 'webp'
|
||||
filters:
|
||||
strip: ~
|
||||
thumbnail: { size: [ 48, 48 ], mode: inset }
|
||||
avatar:
|
||||
quality: 80
|
||||
format: 'webp'
|
||||
filters:
|
||||
strip: ~
|
||||
downscale: { max: [ 128, 128 ] }
|
||||
avatar_small:
|
||||
quality: 80
|
||||
format: 'webp'
|
||||
filters:
|
||||
strip: ~
|
||||
downscale: { max: [ 40, 40 ] }
|
||||
logo:
|
||||
quality: 85
|
||||
format: 'webp'
|
||||
filters:
|
||||
strip: ~
|
||||
thumbnail: { size: [ 99, 56 ], mode: inset }
|
||||
97
config/packages/nelmio_security.yaml
Normal file
97
config/packages/nelmio_security.yaml
Normal file
@@ -0,0 +1,97 @@
|
||||
nelmio_security:
|
||||
|
||||
clickjacking:
|
||||
paths:
|
||||
'^/.*': DENY
|
||||
|
||||
content_type:
|
||||
nosniff: true
|
||||
|
||||
referrer_policy:
|
||||
enabled: true
|
||||
policies:
|
||||
- 'no-referrer'
|
||||
- 'strict-origin-when-cross-origin'
|
||||
|
||||
csp:
|
||||
enforce:
|
||||
level1_fallback: false
|
||||
browser_adaptive:
|
||||
enabled: false
|
||||
report-uri: '%router.request_context.base_url%/my-csp-report'
|
||||
frame-ancestors:
|
||||
- 'self'
|
||||
frame-src:
|
||||
- 'self'
|
||||
- 'https://stripe.com'
|
||||
- 'https://*.stripe.com'
|
||||
- 'https://js.stripe.com'
|
||||
- 'https://cloudflare.com'
|
||||
- 'https://*.cloudflareinsights.com'
|
||||
- 'https://challenges.cloudflare.com'
|
||||
script-src:
|
||||
- 'self'
|
||||
- 'https://static.cloudflareinsights.com'
|
||||
- 'https://challenges.cloudflare.com'
|
||||
- 'https://cdn.jsdelivr.net'
|
||||
- 'https://js.stripe.com'
|
||||
- 'unsafe-inline'
|
||||
style-src:
|
||||
- 'self'
|
||||
- 'https://fonts.googleapis.com'
|
||||
- 'https://cdnjs.cloudflare.com'
|
||||
- 'https://cdn.jsdelivr.net'
|
||||
- 'unsafe-inline'
|
||||
img-src:
|
||||
- 'self'
|
||||
- 'data:'
|
||||
- 'https://*.tile.openstreetmap.org'
|
||||
- 'https://*.basemaps.cartocdn.com'
|
||||
- 'https://cdn.jsdelivr.net'
|
||||
worker-src:
|
||||
- 'self'
|
||||
- 'blob:'
|
||||
connect-src:
|
||||
- 'self'
|
||||
- 'https://cloudflareinsights.com'
|
||||
- 'https://static.cloudflareinsights.com'
|
||||
- 'https://challenges.cloudflare.com'
|
||||
- 'https://nominatim.openstreetmap.org'
|
||||
- 'https://cdn.jsdelivr.net'
|
||||
- 'https://api.stripe.com'
|
||||
font-src:
|
||||
- 'self'
|
||||
- 'https://cdnjs.cloudflare.com'
|
||||
- 'https://fonts.googleapis.com'
|
||||
- 'https://fonts.gstatic.com'
|
||||
object-src:
|
||||
- 'none'
|
||||
form-action:
|
||||
- 'self'
|
||||
- 'https://auth.esy-web.dev'
|
||||
- 'https://*.stripe.com'
|
||||
- 'https://checkout.stripe.com'
|
||||
block-all-mixed-content: true
|
||||
|
||||
permissions_policy:
|
||||
enabled: true
|
||||
policies:
|
||||
payment: ['self']
|
||||
camera: ['self']
|
||||
microphone: []
|
||||
geolocation: ['self']
|
||||
|
||||
external_redirects:
|
||||
override: /external-redirect
|
||||
forward_as: redirUrl
|
||||
log: true
|
||||
allow_list:
|
||||
- cloudflareinsights.com
|
||||
- static.cloudflareinsights.com
|
||||
- stripe.com
|
||||
- connect.stripe.com
|
||||
- checkout.stripe.com
|
||||
- hooks.stripe.com
|
||||
- dashboard.stripe.com
|
||||
- auth.esy-web.dev
|
||||
- challenges.cloudflare.com
|
||||
11
config/packages/packages/asset_mapper.yaml
Normal file
11
config/packages/packages/asset_mapper.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
framework:
|
||||
asset_mapper:
|
||||
# The paths to make available to the asset mapper.
|
||||
paths:
|
||||
- assets/
|
||||
missing_import_mode: strict
|
||||
|
||||
when@prod:
|
||||
framework:
|
||||
asset_mapper:
|
||||
missing_import_mode: warn
|
||||
19
config/packages/packages/cache.yaml
Normal file
19
config/packages/packages/cache.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
framework:
|
||||
cache:
|
||||
# Nom unique de votre application : utilisé pour calculer des espaces de noms stables pour les clés de cache.
|
||||
# Ceci est CRUCIAL pour éviter les collisions de clés si plusieurs applications partagent le même serveur de cache (ex: Redis).
|
||||
# Décommentez et remplacez par une valeur unique à votre projet (ex: "mon_entreprise/mon_app")
|
||||
prefix_seed: 'e-cosplay/contest' # <-- REMPLACEZ CECI PAR UN NOM UNIQUE À VOTRE PROJET
|
||||
|
||||
# En production, utilisez un adaptateur de cache rapide et performant comme Redis.
|
||||
# Assurez-vous que votre serveur Redis est accessible.
|
||||
app: cache.adapter.redis
|
||||
default_redis_provider: '%env(REDIS_DSN)%'
|
||||
# Vous pouvez également optimiser les pools personnalisés pour la production si besoin.
|
||||
pools:
|
||||
my.user_data_cache:
|
||||
adapter: cache.adapter.redis
|
||||
my.api_data_cache:
|
||||
adapter: cache.adapter.redis
|
||||
vite_cache_pool:
|
||||
adapter: cache.adapter.redis
|
||||
11
config/packages/packages/csrf.yaml
Normal file
11
config/packages/packages/csrf.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
# Enable stateless CSRF protection for forms and logins/logouts
|
||||
framework:
|
||||
form:
|
||||
csrf_protection:
|
||||
token_id: submit
|
||||
|
||||
csrf_protection:
|
||||
stateless_token_ids:
|
||||
- submit
|
||||
- authenticate
|
||||
- logout
|
||||
5
config/packages/packages/debug.yaml
Normal file
5
config/packages/packages/debug.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
when@dev:
|
||||
debug:
|
||||
# Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser.
|
||||
# See the "server:dump" command to start a new server.
|
||||
dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"
|
||||
8
config/packages/packages/dev/nelmio_security.yaml
Normal file
8
config/packages/packages/dev/nelmio_security.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
nelmio_security:
|
||||
csp:
|
||||
enforce:
|
||||
script-src:
|
||||
- "http://localhost:5173"
|
||||
connect-src:
|
||||
- "ws://localhost:5173/" # Autorise le WebSocket de Vite
|
||||
|
||||
3
config/packages/packages/dev/pwa.yaml
Normal file
3
config/packages/packages/dev/pwa.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
pwa:
|
||||
serviceworker:
|
||||
enabled: false
|
||||
54
config/packages/packages/doctrine.yaml
Normal file
54
config/packages/packages/doctrine.yaml
Normal file
@@ -0,0 +1,54 @@
|
||||
doctrine:
|
||||
dbal:
|
||||
url: '%env(resolve:DATABASE_URL)%'
|
||||
|
||||
# IMPORTANT: You MUST configure your server version,
|
||||
# either here or in the DATABASE_URL env var (see .env file)
|
||||
#server_version: '16'
|
||||
|
||||
profiling_collect_backtrace: '%kernel.debug%'
|
||||
use_savepoints: true
|
||||
orm:
|
||||
auto_generate_proxy_classes: true
|
||||
enable_lazy_ghost_objects: true
|
||||
report_fields_where_declared: true
|
||||
validate_xml_mapping: true
|
||||
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
|
||||
identity_generation_preferences:
|
||||
Doctrine\DBAL\Platforms\PostgreSQLPlatform: identity
|
||||
auto_mapping: true
|
||||
mappings:
|
||||
App:
|
||||
type: attribute
|
||||
is_bundle: false
|
||||
dir: '%kernel.project_dir%/src/Entity'
|
||||
prefix: 'App\Entity'
|
||||
alias: App
|
||||
controller_resolver:
|
||||
auto_mapping: false
|
||||
|
||||
when@test:
|
||||
doctrine:
|
||||
dbal:
|
||||
# "TEST_TOKEN" is typically set by ParaTest
|
||||
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
|
||||
|
||||
when@prod:
|
||||
doctrine:
|
||||
orm:
|
||||
auto_generate_proxy_classes: false
|
||||
proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies'
|
||||
query_cache_driver:
|
||||
type: pool
|
||||
pool: doctrine.system_cache_pool
|
||||
result_cache_driver:
|
||||
type: pool
|
||||
pool: doctrine.result_cache_pool
|
||||
|
||||
framework:
|
||||
cache:
|
||||
pools:
|
||||
doctrine.result_cache_pool:
|
||||
adapter: cache.app
|
||||
doctrine.system_cache_pool:
|
||||
adapter: cache.system
|
||||
6
config/packages/packages/doctrine_migrations.yaml
Normal file
6
config/packages/packages/doctrine_migrations.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
doctrine_migrations:
|
||||
migrations_paths:
|
||||
# namespace is arbitrary but should be different from App\Migrations
|
||||
# as migrations classes should NOT be autoloaded
|
||||
'DoctrineMigrations': '%kernel.project_dir%/migrations'
|
||||
enable_profiler: false
|
||||
7
config/packages/packages/flysystem.yaml
Normal file
7
config/packages/packages/flysystem.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
# Read the documentation at https://github.com/thephpleague/flysystem-bundle/blob/master/docs/1-getting-started.md
|
||||
flysystem:
|
||||
storages:
|
||||
default.storage:
|
||||
adapter: 'local'
|
||||
options:
|
||||
directory: '%kernel.project_dir%/var/storage/default'
|
||||
24
config/packages/packages/framework.yaml
Normal file
24
config/packages/packages/framework.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
# see https://symfony.com/doc/current/reference/configuration/framework.html
|
||||
framework:
|
||||
secret: '%env(APP_SECRET)%'
|
||||
|
||||
http_cache:
|
||||
enabled: true
|
||||
default_ttl: 3600
|
||||
stale_while_revalidate: 3600
|
||||
stale_if_error: 3600
|
||||
session:
|
||||
name: ecosplay_session
|
||||
cookie_lifetime: 3600
|
||||
cookie_secure: true
|
||||
|
||||
#esi: true
|
||||
#fragments: true
|
||||
trusted_proxies: '103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,104.16.0.0/13,104.24.0.0/14,108.162.192.0/18,131.0.72.0/22,141.101.64.0/18,162.158.0.0/15,172.64.0.0/13,173.245.48.0/20,188.114.96.0/20,190.93.240.0/20,197.234.240.0/22,198.41.128.0/17'
|
||||
trusted_headers: [ 'x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix' ]
|
||||
|
||||
when@test:
|
||||
framework:
|
||||
test: true
|
||||
session:
|
||||
storage_factory_id: session.storage.factory.mock_file
|
||||
11
config/packages/packages/google_apiclient.yaml
Normal file
11
config/packages/packages/google_apiclient.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
services:
|
||||
Google\Client:
|
||||
class: Google\Client
|
||||
calls:
|
||||
# Authentication with "API key"
|
||||
- [setDeveloperKey, ['%env(GOOGLE_API_KEY)%']]
|
||||
# Authentication with "OAuth 2.0" using Client ID & Secret
|
||||
- [setClientId, ['%env(GOOGLE_CLIENT_ID)%']]
|
||||
- [setClientSecret, ['%env(GOOGLE_CLIENT_SECRET)%']]
|
||||
# Authentication with "OAuth 2.0" or "Service account" using JSON
|
||||
- [setAuthConfig, ['%env(resolve:GOOGLE_AUTH_CONFIG)%']]
|
||||
9
config/packages/packages/knpu_oauth2_client.yaml
Normal file
9
config/packages/packages/knpu_oauth2_client.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
knpu_oauth2_client:
|
||||
clients:
|
||||
keycloak:
|
||||
type: keycloak
|
||||
auth_server_url: '%env(OAUTH_KEYCLOAK_URL)%'
|
||||
realm: '%env(OAUTH_KEYCLOAK_REALM)%'
|
||||
client_id: '%env(OAUTH_KEYCLOAK_CLIENT_ID)%'
|
||||
client_secret: '%env(OAUTH_KEYCLOAK_CLIENT_SECRET)%'
|
||||
redirect_route: connect_keycloak_check
|
||||
28
config/packages/packages/liip_imagine.yaml
Normal file
28
config/packages/packages/liip_imagine.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
liip_imagine:
|
||||
driver: "gd"
|
||||
twig:
|
||||
mode: lazy
|
||||
filter_sets:
|
||||
webp:
|
||||
quality: 85
|
||||
format: 'webp'
|
||||
filters:
|
||||
strip: ~
|
||||
avatar_partner:
|
||||
quality: 75
|
||||
format: 'webp'
|
||||
filters:
|
||||
strip: ~
|
||||
thumbnail: { size: [ 128, 128 ], mode: inset }
|
||||
members:
|
||||
quality: 75
|
||||
format: 'webp'
|
||||
filters:
|
||||
strip: ~
|
||||
thumbnail: { size: [ 128, 128 ], mode: inset }
|
||||
logo:
|
||||
quality: 85
|
||||
format: 'webp'
|
||||
filters:
|
||||
strip: ~
|
||||
thumbnail: { size: [ 99, 56 ], mode: inset }
|
||||
3
config/packages/packages/mailer.yaml
Normal file
3
config/packages/packages/mailer.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
framework:
|
||||
mailer:
|
||||
dsn: '%env(MAILER_DSN)%'
|
||||
8
config/packages/packages/messenger.yaml
Normal file
8
config/packages/packages/messenger.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
# config/packages/messenger.yaml
|
||||
framework:
|
||||
messenger:
|
||||
transports:
|
||||
async: "%env(MESSENGER_TRANSPORT_DSN)%"
|
||||
|
||||
routing:
|
||||
|
||||
51
config/packages/packages/monolog.yaml
Normal file
51
config/packages/packages/monolog.yaml
Normal file
@@ -0,0 +1,51 @@
|
||||
monolog:
|
||||
channels:
|
||||
- deprecation # Deprecations are logged in the dedicated "deprecation" channel when it exists
|
||||
|
||||
when@dev:
|
||||
monolog:
|
||||
handlers:
|
||||
main:
|
||||
type: stream
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||
level: debug
|
||||
channels: ["!event"]
|
||||
# uncomment to get logging in your browser
|
||||
# you may have to allow bigger header sizes in your Web server configuration
|
||||
#firephp:
|
||||
# type: firephp
|
||||
# level: info
|
||||
#chromephp:
|
||||
# type: chromephp
|
||||
# level: info
|
||||
console:
|
||||
type: console
|
||||
process_psr_3_messages: false
|
||||
channels: ["!event", "!doctrine", "!console"]
|
||||
|
||||
when@test:
|
||||
monolog:
|
||||
handlers:
|
||||
main:
|
||||
type: fingers_crossed
|
||||
action_level: error
|
||||
handler: nested
|
||||
excluded_http_codes: [404, 405]
|
||||
channels: ["!event"]
|
||||
nested:
|
||||
type: stream
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||
level: debug
|
||||
|
||||
when@prod:
|
||||
monolog:
|
||||
handlers:
|
||||
main:
|
||||
type: stream
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||
level: debug
|
||||
channels: ["!event"]
|
||||
console:
|
||||
type: console
|
||||
process_psr_3_messages: false
|
||||
channels: ["!event", "!doctrine", "!console"]
|
||||
10
config/packages/packages/nelmio_cors.yaml
Normal file
10
config/packages/packages/nelmio_cors.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
nelmio_cors:
|
||||
defaults:
|
||||
origin_regex: true
|
||||
allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
|
||||
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
|
||||
allow_headers: ['Content-Type', 'Authorization']
|
||||
expose_headers: ['Link']
|
||||
max_age: 3600
|
||||
paths:
|
||||
'^/': null
|
||||
62
config/packages/packages/nelmio_security.yaml
Normal file
62
config/packages/packages/nelmio_security.yaml
Normal file
@@ -0,0 +1,62 @@
|
||||
nelmio_security:
|
||||
# Content Security Policy (CSP)
|
||||
referrer_policy:
|
||||
enabled: true
|
||||
policies:
|
||||
- 'strict-origin-when-cross-origin'
|
||||
permissions_policy:
|
||||
enabled: true
|
||||
policies:
|
||||
camera: [self] # Correct : sans les guillemets simples internes
|
||||
microphone: [self] # Correct
|
||||
geolocation: [self] # Correct
|
||||
fullscreen: [self] # Correct
|
||||
payment: [self] # Correct
|
||||
# Si tu veux bloquer une fonction pour tout le monde :
|
||||
usb: []
|
||||
csp:
|
||||
hash:
|
||||
algorithm: 'sha256'
|
||||
enforce:
|
||||
default-src: ["'self'"]
|
||||
worker-src: ["'self'"]
|
||||
script-src:
|
||||
- "'self'"
|
||||
- "nonce"
|
||||
- "https://sentry.esy-web.dev"
|
||||
- "https://chat.esy-web.dev"
|
||||
- "https://static.cloudflareinsights.com"
|
||||
- "https://challenges.cloudflare.com"
|
||||
connect-src:
|
||||
- "'self'"
|
||||
- "https://sentry.esy-web.dev"
|
||||
- "https://chat.esy-web.dev"
|
||||
- "https://auth.esy-web.dev"
|
||||
- "https://cloudflareinsights.com"
|
||||
- "https://challenges.cloudflare.com"
|
||||
- "https://tools-security.esy-web.dev"
|
||||
- "https://checkout.stripe.com/"
|
||||
- "https://cdnjs.cloudflare.com"
|
||||
frame-src:
|
||||
- "'self'"
|
||||
- "https://chat.esy-web.dev"
|
||||
- "https://challenges.cloudflare.com"
|
||||
- "https://climate.stripe.com/"
|
||||
style-src:
|
||||
- "'self'"
|
||||
- "'unsafe-inline'"
|
||||
- "https://fonts.googleapis.com"
|
||||
- "https://chat.esy-web.dev"
|
||||
- "https://cdnjs.cloudflare.com"
|
||||
img-src:
|
||||
- "'self'"
|
||||
- "data:"
|
||||
- "https://chat.esy-web.dev"
|
||||
font-src:
|
||||
- "'self'"
|
||||
- "data:"
|
||||
- 'https://fonts.gstatic.com'
|
||||
- "https://cdnjs.cloudflare.com/"
|
||||
frame-ancestors: ["'none'"]
|
||||
# Optionnel : forcer le passage en HTTPS
|
||||
upgrade-insecure-requests: false
|
||||
12
config/packages/packages/notifier.yaml
Normal file
12
config/packages/packages/notifier.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
framework:
|
||||
notifier:
|
||||
chatter_transports:
|
||||
texter_transports:
|
||||
channel_policy:
|
||||
# use chat/slack, chat/telegram, sms/twilio or sms/nexmo
|
||||
urgent: ['email']
|
||||
high: ['email']
|
||||
medium: ['email']
|
||||
low: ['email']
|
||||
admin_recipients:
|
||||
- { email: admin@example.com }
|
||||
@@ -0,0 +1,3 @@
|
||||
pixel_open_cloudflare_turnstile:
|
||||
key: "%env(TURNSTILE_KEY)%"
|
||||
secret: "%env(TURNSTILE_SECRET)%"
|
||||
3
config/packages/packages/presta_sitemap.yaml
Normal file
3
config/packages/packages/presta_sitemap.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
presta_sitemap:
|
||||
sitemap_file_prefix: 'sitemap'
|
||||
timetolive: 3600
|
||||
3
config/packages/packages/property_info.yaml
Normal file
3
config/packages/packages/property_info.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
framework:
|
||||
property_info:
|
||||
with_constructor_extractor: true
|
||||
23
config/packages/packages/pwa.yaml
Normal file
23
config/packages/packages/pwa.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
pwa:
|
||||
asset_compiler: false # Default to true. Will change to false in 2.0.0.
|
||||
image_processor: 'pwa.image_processor.gd' # Or 'pwa.image_processor.gd'
|
||||
favicons:
|
||||
enabled: true
|
||||
src: '%kernel.project_dir%/public/assets/notif.png'
|
||||
serviceworker:
|
||||
enabled: true
|
||||
scope: "/"
|
||||
use_cache: false
|
||||
skip_waiting: true
|
||||
manifest:
|
||||
enabled: true
|
||||
name: "E-Cosplay"
|
||||
short_name: "PWA"
|
||||
start_url: "app_home"
|
||||
display: "standalone"
|
||||
background_color: "#ffffff"
|
||||
theme_color: "#4285f4"
|
||||
categories: ['games','multimedia','social networking']
|
||||
icons:
|
||||
- src: '%kernel.project_dir%/public/assets/notif.png'
|
||||
sizes: [192]
|
||||
10
config/packages/packages/routing.yaml
Normal file
10
config/packages/packages/routing.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
framework:
|
||||
router:
|
||||
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
|
||||
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
|
||||
#default_uri: http://localhost
|
||||
|
||||
when@prod:
|
||||
framework:
|
||||
router:
|
||||
strict_requirements: null
|
||||
50
config/packages/packages/security.yaml
Normal file
50
config/packages/packages/security.yaml
Normal file
@@ -0,0 +1,50 @@
|
||||
# config/packages/security.yaml
|
||||
security:
|
||||
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
|
||||
providers:
|
||||
# Appelle votre provider d'utilisateurs.
|
||||
# Ici, nous configurons un provider d'entité pour notre classe Account,
|
||||
# en spécifiant 'username' comme propriété d'identification.
|
||||
app_account_provider:
|
||||
entity:
|
||||
class: App\Entity\Account
|
||||
property: email # Utilise le champ 'username' de votre entité Account pour l'authentification
|
||||
|
||||
firewalls:
|
||||
dev:
|
||||
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||
security: false
|
||||
|
||||
main:
|
||||
lazy: true
|
||||
provider: app_account_provider # Utilise le provider que nous avons défini ci-dessus
|
||||
user_checker: App\Security\UserChecker
|
||||
form_login:
|
||||
login_path: app_login # La route vers votre formulaire de connexion (GET)
|
||||
check_path: app_login # L'URL où le formulaire POST sera soumis
|
||||
enable_csrf: true # Active la protection CSRF
|
||||
csrf_token_id: authenticate # ID du jeton CSRF (doit correspondre à celui dans votre Twig)
|
||||
entry_point: App\Security\AuthenticationEntryPoint
|
||||
custom_authenticator:
|
||||
- App\Security\LoginFormAuthenticator
|
||||
- App\Security\KeycloakAuthenticator
|
||||
- App\Security\DiscordAuthenticator
|
||||
logout:
|
||||
target: app_logout
|
||||
|
||||
# Configuration des algorithmes de hachage des mots de passe.
|
||||
# Symfony choisira automatiquement le meilleur algorithme par défaut si non spécifié,
|
||||
# mais vous pouvez le configurer explicitement.
|
||||
password_hashers:
|
||||
App\Entity\Account: 'auto' # 'auto' sélectionne le meilleur algorithme disponible (recommandé)
|
||||
# Ou pour spécifier bcrypt explicitement :
|
||||
# App\Entity\Account:
|
||||
# algorithm: bcrypt
|
||||
|
||||
role_hierarchy:
|
||||
ROLE_ROOT: [ROLE_ADMIN] # ROLE_ROOT inclut ROLE_ADMIN, qui à son tour inclut ROLE_ARTEMIS
|
||||
|
||||
|
||||
access_control:
|
||||
- { path: ^/admin, roles: [ROLE_ADMIN] }
|
||||
- { path: ^/, roles: PUBLIC_ACCESS } # Toutes les autres pages nécessitent une authentification complète
|
||||
36
config/packages/packages/sentry.yaml
Normal file
36
config/packages/packages/sentry.yaml
Normal file
@@ -0,0 +1,36 @@
|
||||
when@prod:
|
||||
sentry:
|
||||
dsn: '%env(SENTRY_DSN)%'
|
||||
options:
|
||||
# Add request headers, cookies, IP address and the authenticated user
|
||||
# see https://docs.sentry.io/platforms/php/data-management/data-collected/ for more info
|
||||
# send_default_pii: true
|
||||
ignore_exceptions:
|
||||
- 'Symfony\Component\ErrorHandler\Error\FatalError'
|
||||
- 'Symfony\Component\Debug\Exception\FatalErrorException'
|
||||
#
|
||||
# # If you are using Monolog, you also need this additional configuration to log the errors correctly:
|
||||
# # https://docs.sentry.io/platforms/php/guides/symfony/#monolog-integration
|
||||
# register_error_listener: false
|
||||
# register_error_handler: false
|
||||
#
|
||||
# monolog:
|
||||
# handlers:
|
||||
# # Use this only if you don't want to use structured logging and instead receive
|
||||
# # certain log levels as errors.
|
||||
# sentry:
|
||||
# type: sentry
|
||||
# level: !php/const Monolog\Logger::ERROR
|
||||
# hub_id: Sentry\State\HubInterface
|
||||
# fill_extra_context: true # Enables sending monolog context to Sentry
|
||||
# process_psr_3_messages: false # Disables the resolution of PSR-3 placeholders
|
||||
#
|
||||
# # Use this for structured log integration
|
||||
# sentry_logs:
|
||||
# type: service
|
||||
# id: Sentry\SentryBundle\Monolog\LogsHandler
|
||||
#
|
||||
# services:
|
||||
# Sentry\SentryBundle\Monolog\LogsHandler:
|
||||
# arguments:
|
||||
# - !php/const Monolog\Logger::INFO
|
||||
7
config/packages/packages/stripe.yaml
Normal file
7
config/packages/packages/stripe.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
services:
|
||||
stripe.client:
|
||||
class: 'Stripe\StripeClient'
|
||||
arguments:
|
||||
- '%env(STRIPE_SECRET_KEY)%'
|
||||
|
||||
Stripe\StripeClient: '@stripe.client'
|
||||
5
config/packages/packages/translation.yaml
Normal file
5
config/packages/packages/translation.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
framework:
|
||||
default_locale: fr
|
||||
translator:
|
||||
default_path: '%kernel.project_dir%/translations'
|
||||
providers:
|
||||
7
config/packages/packages/twig.yaml
Normal file
7
config/packages/packages/twig.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
twig:
|
||||
file_name_pattern: '*.twig'
|
||||
form_themes:
|
||||
- 'form_tailwind.twig'
|
||||
when@test:
|
||||
twig:
|
||||
strict_variables: true
|
||||
11
config/packages/packages/validator.yaml
Normal file
11
config/packages/packages/validator.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
framework:
|
||||
validation:
|
||||
# Enables validator auto-mapping support.
|
||||
# For instance, basic validation constraints will be inferred from Doctrine's metadata.
|
||||
#auto_mapping:
|
||||
# App\Entity\: []
|
||||
|
||||
when@test:
|
||||
framework:
|
||||
validation:
|
||||
not_compromised_password: false
|
||||
96
config/packages/packages/vich_uploader.yaml
Normal file
96
config/packages/packages/vich_uploader.yaml
Normal file
@@ -0,0 +1,96 @@
|
||||
vich_uploader:
|
||||
db_driver: orm
|
||||
mappings:
|
||||
avatar:
|
||||
uri_prefix: /storage/avatar
|
||||
upload_destination: '%kernel.project_dir%/public/storage/avatar'
|
||||
namer: App\VichUploader\Namer\Account\AvatarName # Replaced namer
|
||||
directory_namer: App\VichUploader\DirectoryNamer\Account\AvatarName
|
||||
inject_on_load: true
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
members:
|
||||
uri_prefix: /storage/members
|
||||
upload_destination: '%kernel.project_dir%/public/storage/members'
|
||||
namer: App\VichUploader\Namer\Account\AvatarName # Replaced namer
|
||||
directory_namer: App\VichUploader\DirectoryNamer\Account\AvatarName
|
||||
inject_on_load: true
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
members_page_avatar:
|
||||
uri_prefix: /storage/members_page_avatar
|
||||
upload_destination: '%kernel.project_dir%/public/storage/members_page_avatar'
|
||||
namer: Vich\UploaderBundle\Naming\UniqidNamer
|
||||
inject_on_load: true
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
members_page_cosplay:
|
||||
uri_prefix: /storage/members_page_avatar
|
||||
upload_destination: '%kernel.project_dir%/public/storage/members_page_avatar'
|
||||
namer: Vich\UploaderBundle\Naming\UniqidNamer
|
||||
inject_on_load: true
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
members_page_cosplay_details:
|
||||
uri_prefix: /storage/members_page_cosplay_details
|
||||
upload_destination: '%kernel.project_dir%/public/storage/members_page_cosplay_details'
|
||||
namer: Vich\UploaderBundle\Naming\UniqidNamer
|
||||
inject_on_load: true
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
ag:
|
||||
uri_prefix: /storage/ag
|
||||
upload_destination: '%kernel.project_dir%/public/storage/ag'
|
||||
namer: Vich\UploaderBundle\Naming\UniqidNamer # Replaced namer
|
||||
inject_on_load: true
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
ag_adh:
|
||||
uri_prefix: /storage/ag_adh
|
||||
upload_destination: '%kernel.project_dir%/public/storage/ag_adh'
|
||||
namer: Vich\UploaderBundle\Naming\UniqidNamer # Replaced namer
|
||||
inject_on_load: true
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
product:
|
||||
uri_prefix: /storage/product
|
||||
upload_destination: '%kernel.project_dir%/public/storage/product'
|
||||
namer: Vich\UploaderBundle\Naming\UniqidNamer # Replaced namer
|
||||
inject_on_load: true
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
events:
|
||||
uri_prefix: /storage/events
|
||||
upload_destination: '%kernel.project_dir%/public/storage/events'
|
||||
namer: Vich\UploaderBundle\Naming\UniqidNamer # Replaced namer
|
||||
inject_on_load: true
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
event_picture:
|
||||
uri_prefix: /event_picture/events
|
||||
upload_destination: '%kernel.project_dir%/public/storage/event_picture'
|
||||
namer: Vich\UploaderBundle\Naming\UniqidNamer # Replaced namer
|
||||
directory_namer: App\VichUploader\DirectoryNamer\EventName
|
||||
inject_on_load: true
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
epage_avatar:
|
||||
uri_prefix: /storage/epage/
|
||||
upload_destination: '%kernel.project_dir%/public/storage/epage'
|
||||
namer: App\VichUploader\Namer\Epage\AvatarNamer # Replaced namer
|
||||
directory_namer: App\VichUploader\DirectoryNamer\Epage\DirectoryNamer
|
||||
inject_on_load: true
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
fiche:
|
||||
uri_prefix: /storage/fiche_candidat
|
||||
upload_destination: '%kernel.project_dir%/public/storage/fiche_candidat'
|
||||
namer: Vich\UploaderBundle\Naming\UniqidNamer # Replaced namer
|
||||
inject_on_load: true
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
#mappings:
|
||||
# products:
|
||||
# uri_prefix: /images/products
|
||||
# upload_destination: '%kernel.project_dir%/public/images/products'
|
||||
# namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
|
||||
13
config/packages/packages/web_profiler.yaml
Normal file
13
config/packages/packages/web_profiler.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
when@dev:
|
||||
web_profiler:
|
||||
toolbar: true
|
||||
intercept_redirects: false
|
||||
framework:
|
||||
profiler:
|
||||
collect_serializer_data: true
|
||||
|
||||
when@test:
|
||||
framework:
|
||||
profiler:
|
||||
collect: false
|
||||
collect_serializer_data: true
|
||||
22
config/packages/prod/nelmio_security.yaml
Normal file
22
config/packages/prod/nelmio_security.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
nelmio_security:
|
||||
csp:
|
||||
enforce:
|
||||
script-src:
|
||||
- 'self'
|
||||
- 'nonce'
|
||||
- 'https://static.cloudflareinsights.com'
|
||||
- 'https://challenges.cloudflare.com'
|
||||
|
||||
# Restreindre les soumissions de formulaires à notre domaine
|
||||
# et aux redirections OAuth des plateformes de partage social
|
||||
form-action:
|
||||
- 'self'
|
||||
- 'https://www.facebook.com'
|
||||
- 'https://x.com'
|
||||
- 'https://twitter.com'
|
||||
|
||||
# Autoriser navigator.share() (Web Share API) et clipboard API
|
||||
# — les deux sont des APIs navigateur natives, pas des appels réseau externes
|
||||
# Ce bloc est présent pour documentation et futures intégrations
|
||||
connect-src:
|
||||
- 'self'
|
||||
8
config/packages/pwa.yaml
Normal file
8
config/packages/pwa.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
# Documentation available at https://pwa.spomky-labs.com/
|
||||
## Please add the favicons, manifest or serviceworker sections depending on your needs.
|
||||
pwa:
|
||||
asset_compiler: false
|
||||
image_processor: 'pwa.image_processor.gd'
|
||||
favicons:
|
||||
enabled: true
|
||||
src: '%kernel.project_dir%/public/favicon.png'
|
||||
20
config/packages/scheb_2fa.yaml
Normal file
20
config/packages/scheb_2fa.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
scheb_two_factor:
|
||||
security_tokens:
|
||||
- Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken
|
||||
- Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken
|
||||
|
||||
email:
|
||||
enabled: true
|
||||
sender_email: 'contact@e-cosplay.fr'
|
||||
sender_name: 'CRM Ecosplay'
|
||||
digits: 6
|
||||
template: 'security/2fa_email.html.twig'
|
||||
mailer: App\Security\TwoFactorCodeMailer
|
||||
|
||||
google:
|
||||
enabled: true
|
||||
issuer: 'CRM Ecosplay'
|
||||
template: 'security/2fa_google.html.twig'
|
||||
|
||||
backup_codes:
|
||||
enabled: true
|
||||
@@ -5,27 +5,53 @@ security:
|
||||
|
||||
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
||||
providers:
|
||||
users_in_memory: { memory: null }
|
||||
app_user_provider:
|
||||
entity:
|
||||
class: App\Entity\User
|
||||
property: email
|
||||
|
||||
firewalls:
|
||||
dev:
|
||||
# Ensure dev tools and static assets are always allowed
|
||||
pattern: ^/(_profiler|_wdt|assets|build)/
|
||||
security: false
|
||||
webhooks:
|
||||
pattern: ^/webhooks/
|
||||
security: false
|
||||
main:
|
||||
lazy: true
|
||||
provider: users_in_memory
|
||||
provider: app_user_provider
|
||||
entry_point: form_login
|
||||
custom_authenticators:
|
||||
- App\Security\KeycloakAuthenticator
|
||||
form_login:
|
||||
login_path: app_home
|
||||
check_path: app_home
|
||||
username_parameter: _username
|
||||
password_parameter: _password
|
||||
success_handler: App\Security\LoginSuccessHandler
|
||||
logout:
|
||||
path: app_logout
|
||||
two_factor:
|
||||
auth_form_path: 2fa_login
|
||||
check_path: 2fa_login_check
|
||||
default_target_path: app_home
|
||||
prepare_on_login: true
|
||||
prepare_on_access_denied: true
|
||||
enable_csrf: true
|
||||
|
||||
# Activate different ways to authenticate:
|
||||
# https://symfony.com/doc/current/security.html#the-firewall
|
||||
|
||||
# https://symfony.com/doc/current/security/impersonating_user.html
|
||||
# switch_user: true
|
||||
role_hierarchy:
|
||||
ROLE_CUSTOMER: ROLE_USER
|
||||
ROLE_REVENDEUR: ROLE_CUSTOMER
|
||||
ROLE_MEMBER: ROLE_USER
|
||||
ROLE_EMPLOYE: ROLE_MEMBER
|
||||
ROLE_ROOT: [ROLE_EMPLOYE, ROLE_REVENDEUR]
|
||||
|
||||
# Note: Only the *first* matching rule is applied
|
||||
access_control:
|
||||
# - { path: ^/admin, roles: ROLE_ADMIN }
|
||||
# - { path: ^/profile, roles: ROLE_USER }
|
||||
- { path: ^/2fa, role: IS_AUTHENTICATED_2FA_IN_PROGRESS }
|
||||
- { path: ^/admin, roles: ROLE_EMPLOYE }
|
||||
- { path: ^/espace-client, roles: ROLE_CUSTOMER }
|
||||
- { path: ^/espace-prestataire, roles: ROLE_REVENDEUR }
|
||||
|
||||
when@test:
|
||||
security:
|
||||
|
||||
7
config/packages/stripe.yaml
Normal file
7
config/packages/stripe.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
services:
|
||||
stripe.client:
|
||||
class: 'Stripe\StripeClient'
|
||||
arguments:
|
||||
- '%env(STRIPE_SECRET_KEY)%'
|
||||
|
||||
Stripe\StripeClient: '@stripe.client'
|
||||
@@ -1,4 +0,0 @@
|
||||
# Enable stateless CSRF protection for forms and logins/logouts
|
||||
framework:
|
||||
csrf_protection:
|
||||
check_header: true
|
||||
8
config/packages/vich_uploader.yaml
Normal file
8
config/packages/vich_uploader.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
vich_uploader:
|
||||
db_driver: orm
|
||||
|
||||
mappings:
|
||||
user_avatar:
|
||||
uri_prefix: /uploads/avatars
|
||||
upload_destination: '%kernel.project_dir%/public/uploads/avatars'
|
||||
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
|
||||
@@ -622,7 +622,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* }>,
|
||||
* },
|
||||
* rate_limiter?: bool|array{ // Rate limiter configuration
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* enabled?: bool|Param, // Default: true
|
||||
* limiters?: array<string, array{ // Default: []
|
||||
* lock_factory?: scalar|Param|null, // The service ID of the lock factory used by this limiter (or null to disable locking). // Default: "auto"
|
||||
* cache_pool?: scalar|Param|null, // The cache pool to use for storing the current limiter state. // Default: "cache.rate_limiter"
|
||||
@@ -938,20 +938,6 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* intercept_redirects?: bool|Param, // Default: false
|
||||
* excluded_ajax_paths?: scalar|Param|null, // Default: "^/((index|app(_[\\w]+)?)\\.php/)?_wdt"
|
||||
* }
|
||||
* @psalm-type StimulusConfig = array{
|
||||
* controller_paths?: list<scalar|Param|null>,
|
||||
* controllers_json?: scalar|Param|null, // Default: "%kernel.project_dir%/assets/controllers.json"
|
||||
* }
|
||||
* @psalm-type TurboConfig = array{
|
||||
* broadcast?: bool|array{
|
||||
* enabled?: bool|Param, // Default: true
|
||||
* entity_template_prefixes?: list<scalar|Param|null>,
|
||||
* doctrine_orm?: bool|array{ // Enable the Doctrine ORM integration
|
||||
* enabled?: bool|Param, // Default: true
|
||||
* },
|
||||
* },
|
||||
* default_transport?: scalar|Param|null, // Default: "default"
|
||||
* }
|
||||
* @psalm-type TwigExtraConfig = array{
|
||||
* cache?: bool|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
@@ -966,10 +952,10 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* },
|
||||
* cssinliner?: bool|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* enabled?: bool|Param, // Default: true
|
||||
* },
|
||||
* inky?: bool|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* enabled?: bool|Param, // Default: true
|
||||
* },
|
||||
* string?: bool|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
@@ -1291,6 +1277,28 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* always_remember_me?: bool|Param, // Default: false
|
||||
* remember_me_parameter?: scalar|Param|null, // Default: "_remember_me"
|
||||
* },
|
||||
* two_factor?: array{
|
||||
* check_path?: scalar|Param|null, // Default: "/2fa_check"
|
||||
* post_only?: bool|Param, // Default: true
|
||||
* auth_form_path?: scalar|Param|null, // Default: "/2fa"
|
||||
* always_use_default_target_path?: bool|Param, // Default: false
|
||||
* default_target_path?: scalar|Param|null, // Default: "/"
|
||||
* success_handler?: scalar|Param|null, // Default: null
|
||||
* failure_handler?: scalar|Param|null, // Default: null
|
||||
* authentication_required_handler?: scalar|Param|null, // Default: null
|
||||
* auth_code_parameter_name?: scalar|Param|null, // Default: "_auth_code"
|
||||
* trusted_parameter_name?: scalar|Param|null, // Default: "_trusted"
|
||||
* remember_me_sets_trusted?: scalar|Param|null, // Default: false
|
||||
* multi_factor?: bool|Param, // Default: false
|
||||
* prepare_on_login?: bool|Param, // Default: false
|
||||
* prepare_on_access_denied?: bool|Param, // Default: false
|
||||
* enable_csrf?: scalar|Param|null, // Default: false
|
||||
* csrf_parameter?: scalar|Param|null, // Default: "_csrf_token"
|
||||
* csrf_token_id?: scalar|Param|null, // Default: "two_factor"
|
||||
* csrf_header?: scalar|Param|null, // Default: null
|
||||
* csrf_token_manager?: scalar|Param|null, // Default: "scheb_two_factor.csrf_token_manager"
|
||||
* provider?: scalar|Param|null, // Default: null
|
||||
* },
|
||||
* }>,
|
||||
* access_control?: list<array{ // Default: []
|
||||
* request_matcher?: scalar|Param|null, // Default: null
|
||||
@@ -1455,6 +1463,818 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* generate_final_classes?: bool|Param, // Default: true
|
||||
* generate_final_entities?: bool|Param, // Default: false
|
||||
* }
|
||||
* @psalm-type EndroidQrCodeConfig = array<string, mixed>
|
||||
* @psalm-type KnpPaginatorConfig = array{
|
||||
* default_options?: array{
|
||||
* sort_field_name?: scalar|Param|null, // Default: "sort"
|
||||
* sort_direction_name?: scalar|Param|null, // Default: "direction"
|
||||
* filter_field_name?: scalar|Param|null, // Default: "filterField"
|
||||
* filter_value_name?: scalar|Param|null, // Default: "filterValue"
|
||||
* page_name?: scalar|Param|null, // Default: "page"
|
||||
* distinct?: bool|Param, // Default: true
|
||||
* page_out_of_range?: scalar|Param|null, // Default: "ignore"
|
||||
* default_limit?: scalar|Param|null, // Default: 10
|
||||
* },
|
||||
* template?: array{
|
||||
* pagination?: scalar|Param|null, // Default: "@KnpPaginator/Pagination/sliding.html.twig"
|
||||
* rel_links?: scalar|Param|null, // Default: "@KnpPaginator/Pagination/rel_links.html.twig"
|
||||
* filtration?: scalar|Param|null, // Default: "@KnpPaginator/Pagination/filtration.html.twig"
|
||||
* sortable?: scalar|Param|null, // Default: "@KnpPaginator/Pagination/sortable_link.html.twig"
|
||||
* },
|
||||
* page_range?: scalar|Param|null, // Default: 5
|
||||
* page_limit?: scalar|Param|null, // Default: null
|
||||
* convert_exception?: bool|Param, // Default: false
|
||||
* remove_first_page_param?: bool|Param, // Default: false
|
||||
* }
|
||||
* @psalm-type KnpuOauth2ClientConfig = array{
|
||||
* http_client?: scalar|Param|null, // Service id of HTTP client to use (must implement GuzzleHttp\ClientInterface) // Default: null
|
||||
* http_client_options?: array{
|
||||
* timeout?: int|Param,
|
||||
* proxy?: scalar|Param|null,
|
||||
* verify?: bool|Param, // Use only with proxy option set
|
||||
* },
|
||||
* clients?: array<string, array<string, mixed>>,
|
||||
* }
|
||||
* @psalm-type FlysystemConfig = array{
|
||||
* storages?: array<string, array{ // Default: []
|
||||
* adapter: scalar|Param|null,
|
||||
* options?: list<mixed>,
|
||||
* visibility?: scalar|Param|null, // Default: null
|
||||
* directory_visibility?: scalar|Param|null, // Default: null
|
||||
* retain_visibility?: bool|Param|null, // Default: null
|
||||
* case_sensitive?: bool|Param, // Default: true
|
||||
* disable_asserts?: bool|Param, // Default: false
|
||||
* public_url?: list<scalar|Param|null>,
|
||||
* path_normalizer?: scalar|Param|null, // Default: null
|
||||
* public_url_generator?: scalar|Param|null, // Default: null
|
||||
* temporary_url_generator?: scalar|Param|null, // Default: null
|
||||
* read_only?: bool|Param, // Default: false
|
||||
* }>,
|
||||
* }
|
||||
* @psalm-type LiipImagineConfig = array{
|
||||
* resolvers?: array<string, array{ // Default: []
|
||||
* web_path?: array{
|
||||
* web_root?: scalar|Param|null, // Default: "%kernel.project_dir%/public"
|
||||
* cache_prefix?: scalar|Param|null, // Default: "media/cache"
|
||||
* },
|
||||
* aws_s3?: array{
|
||||
* bucket?: scalar|Param|null,
|
||||
* cache?: scalar|Param|null, // Default: false
|
||||
* use_psr_cache?: bool|Param, // Default: false
|
||||
* acl?: scalar|Param|null, // Default: "public-read"
|
||||
* cache_prefix?: scalar|Param|null, // Default: ""
|
||||
* client_id?: scalar|Param|null, // Default: null
|
||||
* client_config?: list<mixed>,
|
||||
* get_options?: array<string, scalar|Param|null>,
|
||||
* put_options?: array<string, scalar|Param|null>,
|
||||
* proxies?: array<string, scalar|Param|null>,
|
||||
* },
|
||||
* flysystem?: array{
|
||||
* filesystem_service?: scalar|Param|null,
|
||||
* cache_prefix?: scalar|Param|null, // Default: ""
|
||||
* root_url?: scalar|Param|null,
|
||||
* visibility?: "public"|"private"|"noPredefinedVisibility"|Param, // Default: "public"
|
||||
* },
|
||||
* }>,
|
||||
* loaders?: array<string, array{ // Default: []
|
||||
* stream?: array{
|
||||
* wrapper?: scalar|Param|null,
|
||||
* context?: scalar|Param|null, // Default: null
|
||||
* },
|
||||
* filesystem?: array{
|
||||
* locator?: "filesystem"|"filesystem_insecure"|Param, // Using the "filesystem_insecure" locator is not recommended due to a less secure resolver mechanism, but is provided for those using heavily symlinked projects. // Default: "filesystem"
|
||||
* data_root?: list<scalar|Param|null>,
|
||||
* allow_unresolvable_data_roots?: bool|Param, // Default: false
|
||||
* bundle_resources?: array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* access_control_type?: "blacklist"|"whitelist"|Param, // Sets the access control method applied to bundle names in "access_control_list" into a blacklist or whitelist. // Default: "blacklist"
|
||||
* access_control_list?: list<scalar|Param|null>,
|
||||
* },
|
||||
* },
|
||||
* flysystem?: array{
|
||||
* filesystem_service?: scalar|Param|null,
|
||||
* },
|
||||
* asset_mapper?: array<mixed>,
|
||||
* chain?: array{
|
||||
* loaders?: list<scalar|Param|null>,
|
||||
* },
|
||||
* }>,
|
||||
* driver?: scalar|Param|null, // Default: "gd"
|
||||
* cache?: scalar|Param|null, // Default: "default"
|
||||
* cache_base_path?: scalar|Param|null, // Default: ""
|
||||
* data_loader?: scalar|Param|null, // Default: "default"
|
||||
* default_image?: scalar|Param|null, // Default: null
|
||||
* default_filter_set_settings?: array{
|
||||
* quality?: scalar|Param|null, // Default: 100
|
||||
* jpeg_quality?: scalar|Param|null, // Default: null
|
||||
* png_compression_level?: scalar|Param|null, // Default: null
|
||||
* png_compression_filter?: scalar|Param|null, // Default: null
|
||||
* format?: scalar|Param|null, // Default: null
|
||||
* animated?: bool|Param, // Default: false
|
||||
* cache?: scalar|Param|null, // Default: null
|
||||
* data_loader?: scalar|Param|null, // Default: null
|
||||
* default_image?: scalar|Param|null, // Default: null
|
||||
* filters?: array<string, array<string, mixed>>,
|
||||
* post_processors?: array<string, array<string, mixed>>,
|
||||
* },
|
||||
* controller?: array{
|
||||
* filter_action?: scalar|Param|null, // Default: "Liip\\ImagineBundle\\Controller\\ImagineController::filterAction"
|
||||
* filter_runtime_action?: scalar|Param|null, // Default: "Liip\\ImagineBundle\\Controller\\ImagineController::filterRuntimeAction"
|
||||
* redirect_response_code?: int|Param, // Default: 302
|
||||
* },
|
||||
* filter_sets?: array<string, array{ // Default: []
|
||||
* quality?: scalar|Param|null,
|
||||
* jpeg_quality?: scalar|Param|null,
|
||||
* png_compression_level?: scalar|Param|null,
|
||||
* png_compression_filter?: scalar|Param|null,
|
||||
* format?: scalar|Param|null,
|
||||
* animated?: bool|Param,
|
||||
* cache?: scalar|Param|null,
|
||||
* data_loader?: scalar|Param|null,
|
||||
* default_image?: scalar|Param|null,
|
||||
* filters?: array<string, array<string, mixed>>,
|
||||
* post_processors?: array<string, array<string, mixed>>,
|
||||
* }>,
|
||||
* twig?: array{
|
||||
* mode?: "none"|"lazy"|"legacy"|Param, // Twig mode: none/lazy/legacy (default) // Default: "legacy"
|
||||
* assets_version?: scalar|Param|null, // Default: null
|
||||
* },
|
||||
* enqueue?: bool|Param, // Enables integration with enqueue if set true. Allows resolve image caches in background by sending messages to MQ. // Default: false
|
||||
* messenger?: bool|array{ // Enables integration with symfony/messenger if set true. Warmup image caches in background by sending messages to MQ.
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* },
|
||||
* templating?: bool|Param, // Enables integration with symfony/templating component // Default: true
|
||||
* webp?: array{
|
||||
* generate?: bool|Param, // Default: false
|
||||
* quality?: int|Param, // Default: 100
|
||||
* cache?: scalar|Param|null, // Default: null
|
||||
* data_loader?: scalar|Param|null, // Default: null
|
||||
* post_processors?: array<string, array<string, mixed>>,
|
||||
* },
|
||||
* }
|
||||
* @psalm-type NelmioSecurityConfig = array{
|
||||
* signed_cookie?: array{
|
||||
* names?: list<scalar|Param|null>,
|
||||
* secret?: scalar|Param|null, // Default: "%kernel.secret%"
|
||||
* hash_algo?: scalar|Param|null,
|
||||
* legacy_hash_algo?: scalar|Param|null, // Fallback algorithm to allow for frictionless hash algorithm upgrades. Use with caution and as a temporary measure as it allows for downgrade attacks. // Default: null
|
||||
* separator?: scalar|Param|null, // Default: "."
|
||||
* },
|
||||
* clickjacking?: array{
|
||||
* hosts?: list<scalar|Param|null>,
|
||||
* paths?: array<string, array{ // Default: {"^/.*":{"header":"DENY"}}
|
||||
* header?: scalar|Param|null, // Default: "DENY"
|
||||
* }>,
|
||||
* content_types?: list<scalar|Param|null>,
|
||||
* },
|
||||
* external_redirects?: array{
|
||||
* abort?: bool|Param, // Default: false
|
||||
* override?: scalar|Param|null, // Default: null
|
||||
* forward_as?: scalar|Param|null, // Default: null
|
||||
* log?: bool|Param, // Default: false
|
||||
* allow_list?: list<scalar|Param|null>,
|
||||
* },
|
||||
* flexible_ssl?: bool|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* cookie_name?: scalar|Param|null, // Default: "auth"
|
||||
* unsecured_logout?: bool|Param, // Default: false
|
||||
* },
|
||||
* forced_ssl?: bool|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* hsts_max_age?: scalar|Param|null, // Default: null
|
||||
* hsts_subdomains?: bool|Param, // Default: false
|
||||
* hsts_preload?: bool|Param, // Default: false
|
||||
* allow_list?: list<scalar|Param|null>,
|
||||
* hosts?: list<scalar|Param|null>,
|
||||
* redirect_status_code?: scalar|Param|null, // Default: 302
|
||||
* },
|
||||
* content_type?: array{
|
||||
* nosniff?: bool|Param, // Default: false
|
||||
* },
|
||||
* xss_protection?: array{ // Deprecated: The "xss_protection" option is deprecated, use Content Security Policy without allowing "unsafe-inline" scripts instead.
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* mode_block?: bool|Param, // Default: false
|
||||
* report_uri?: scalar|Param|null, // Default: null
|
||||
* },
|
||||
* csp?: bool|array{
|
||||
* enabled?: bool|Param, // Default: true
|
||||
* request_matcher?: scalar|Param|null, // Default: null
|
||||
* hosts?: list<scalar|Param|null>,
|
||||
* content_types?: list<scalar|Param|null>,
|
||||
* report_endpoint?: array{
|
||||
* log_channel?: scalar|Param|null, // Default: null
|
||||
* log_formatter?: scalar|Param|null, // Default: "nelmio_security.csp_report.log_formatter"
|
||||
* log_level?: "alert"|"critical"|"debug"|"emergency"|"error"|"info"|"notice"|"warning"|Param, // Default: "notice"
|
||||
* filters?: array{
|
||||
* domains?: bool|Param, // Default: true
|
||||
* schemes?: bool|Param, // Default: true
|
||||
* browser_bugs?: bool|Param, // Default: true
|
||||
* injected_scripts?: bool|Param, // Default: true
|
||||
* },
|
||||
* dismiss?: list<list<"default-src"|"base-uri"|"block-all-mixed-content"|"child-src"|"connect-src"|"font-src"|"form-action"|"frame-ancestors"|"frame-src"|"img-src"|"manifest-src"|"media-src"|"object-src"|"plugin-types"|"script-src"|"style-src"|"upgrade-insecure-requests"|"report-uri"|"worker-src"|"prefetch-src"|"report-to"|"*"|Param>>,
|
||||
* },
|
||||
* compat_headers?: bool|Param, // Default: true
|
||||
* report_logger_service?: scalar|Param|null, // Default: "logger"
|
||||
* hash?: array{
|
||||
* algorithm?: "sha256"|"sha384"|"sha512"|Param, // The algorithm to use for hashes // Default: "sha256"
|
||||
* },
|
||||
* report?: array{
|
||||
* level1_fallback?: bool|Param, // Provides CSP Level 1 fallback when using hash or nonce (CSP level 2) by adding 'unsafe-inline' source. See https://www.w3.org/TR/CSP2/#directive-script-src and https://www.w3.org/TR/CSP2/#directive-style-src // Default: true
|
||||
* browser_adaptive?: bool|array{ // Do not send directives that browser do not support
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* parser?: scalar|Param|null, // Default: "nelmio_security.ua_parser.ua_php"
|
||||
* },
|
||||
* default-src?: list<scalar|Param|null>,
|
||||
* base-uri?: list<scalar|Param|null>,
|
||||
* block-all-mixed-content?: bool|Param, // Default: false
|
||||
* child-src?: list<scalar|Param|null>,
|
||||
* connect-src?: list<scalar|Param|null>,
|
||||
* font-src?: list<scalar|Param|null>,
|
||||
* form-action?: list<scalar|Param|null>,
|
||||
* frame-ancestors?: list<scalar|Param|null>,
|
||||
* frame-src?: list<scalar|Param|null>,
|
||||
* img-src?: list<scalar|Param|null>,
|
||||
* manifest-src?: list<scalar|Param|null>,
|
||||
* media-src?: list<scalar|Param|null>,
|
||||
* object-src?: list<scalar|Param|null>,
|
||||
* plugin-types?: list<scalar|Param|null>,
|
||||
* script-src?: list<scalar|Param|null>,
|
||||
* style-src?: list<scalar|Param|null>,
|
||||
* upgrade-insecure-requests?: bool|Param, // Default: false
|
||||
* report-uri?: list<scalar|Param|null>,
|
||||
* worker-src?: list<scalar|Param|null>,
|
||||
* prefetch-src?: list<scalar|Param|null>,
|
||||
* report-to?: scalar|Param|null,
|
||||
* },
|
||||
* enforce?: array{
|
||||
* level1_fallback?: bool|Param, // Provides CSP Level 1 fallback when using hash or nonce (CSP level 2) by adding 'unsafe-inline' source. See https://www.w3.org/TR/CSP2/#directive-script-src and https://www.w3.org/TR/CSP2/#directive-style-src // Default: true
|
||||
* browser_adaptive?: bool|array{ // Do not send directives that browser do not support
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* parser?: scalar|Param|null, // Default: "nelmio_security.ua_parser.ua_php"
|
||||
* },
|
||||
* default-src?: list<scalar|Param|null>,
|
||||
* base-uri?: list<scalar|Param|null>,
|
||||
* block-all-mixed-content?: bool|Param, // Default: false
|
||||
* child-src?: list<scalar|Param|null>,
|
||||
* connect-src?: list<scalar|Param|null>,
|
||||
* font-src?: list<scalar|Param|null>,
|
||||
* form-action?: list<scalar|Param|null>,
|
||||
* frame-ancestors?: list<scalar|Param|null>,
|
||||
* frame-src?: list<scalar|Param|null>,
|
||||
* img-src?: list<scalar|Param|null>,
|
||||
* manifest-src?: list<scalar|Param|null>,
|
||||
* media-src?: list<scalar|Param|null>,
|
||||
* object-src?: list<scalar|Param|null>,
|
||||
* plugin-types?: list<scalar|Param|null>,
|
||||
* script-src?: list<scalar|Param|null>,
|
||||
* style-src?: list<scalar|Param|null>,
|
||||
* upgrade-insecure-requests?: bool|Param, // Default: false
|
||||
* report-uri?: list<scalar|Param|null>,
|
||||
* worker-src?: list<scalar|Param|null>,
|
||||
* prefetch-src?: list<scalar|Param|null>,
|
||||
* report-to?: scalar|Param|null,
|
||||
* },
|
||||
* },
|
||||
* referrer_policy?: bool|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* policies?: list<scalar|Param|null>,
|
||||
* },
|
||||
* permissions_policy?: bool|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* policies?: array{
|
||||
* accelerometer?: mixed, // Default: null
|
||||
* ambient_light_sensor?: mixed, // Default: null
|
||||
* attribution_reporting?: mixed, // Default: null
|
||||
* autoplay?: mixed, // Default: null
|
||||
* bluetooth?: mixed, // Default: null
|
||||
* browsing_topics?: mixed, // Default: null
|
||||
* camera?: mixed, // Default: null
|
||||
* captured_surface_control?: mixed, // Default: null
|
||||
* compute_pressure?: mixed, // Default: null
|
||||
* cross_origin_isolated?: mixed, // Default: null
|
||||
* deferred_fetch?: mixed, // Default: null
|
||||
* deferred_fetch_minimal?: mixed, // Default: null
|
||||
* display_capture?: mixed, // Default: null
|
||||
* encrypted_media?: mixed, // Default: null
|
||||
* fullscreen?: mixed, // Default: null
|
||||
* gamepad?: mixed, // Default: null
|
||||
* geolocation?: mixed, // Default: null
|
||||
* gyroscope?: mixed, // Default: null
|
||||
* hid?: mixed, // Default: null
|
||||
* identity_credentials_get?: mixed, // Default: null
|
||||
* idle_detection?: mixed, // Default: null
|
||||
* interest_cohort?: mixed, // Default: null
|
||||
* language_detector?: mixed, // Default: null
|
||||
* local_fonts?: mixed, // Default: null
|
||||
* magnetometer?: mixed, // Default: null
|
||||
* microphone?: mixed, // Default: null
|
||||
* midi?: mixed, // Default: null
|
||||
* otp_credentials?: mixed, // Default: null
|
||||
* payment?: mixed, // Default: null
|
||||
* picture_in_picture?: mixed, // Default: null
|
||||
* publickey_credentials_create?: mixed, // Default: null
|
||||
* publickey_credentials_get?: mixed, // Default: null
|
||||
* screen_wake_lock?: mixed, // Default: null
|
||||
* serial?: mixed, // Default: null
|
||||
* speaker_selection?: mixed, // Default: null
|
||||
* storage_access?: mixed, // Default: null
|
||||
* summarizer?: mixed, // Default: null
|
||||
* translator?: mixed, // Default: null
|
||||
* usb?: mixed, // Default: null
|
||||
* web_share?: mixed, // Default: null
|
||||
* window_management?: mixed, // Default: null
|
||||
* xr_spatial_tracking?: mixed, // Default: null
|
||||
* },
|
||||
* },
|
||||
* cross_origin_isolation?: bool|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* paths?: array<string, array{ // Default: []
|
||||
* coep?: "unsafe-none"|"require-corp"|"credentialless"|Param, // Cross-Origin-Embedder-Policy (COEP) header value
|
||||
* coop?: "unsafe-none"|"same-origin-allow-popups"|"same-origin"|"noopener-allow-popups"|Param, // Cross-Origin-Opener-Policy (COOP) header value
|
||||
* corp?: "same-site"|"same-origin"|"cross-origin"|Param, // Cross-Origin-Resource-Policy (CORP) header value
|
||||
* report_only?: bool|Param, // Use Report-Only headers instead of enforcing (applies to COEP and COOP only) // Default: false
|
||||
* report_to?: scalar|Param|null, // Reporting endpoint name for violations (requires Reporting API configuration, applies to COEP and COOP only) // Default: null
|
||||
* }>,
|
||||
* },
|
||||
* }
|
||||
* @psalm-type PwaConfig = array{
|
||||
* asset_compiler?: bool|Param, // When true, the assets will be compiled when the command "asset-map:compile" is run. // Default: true
|
||||
* early_hints?: bool|array{ // Early Hints (HTTP 103) configuration. Requires a compatible server (FrankenPHP, Caddy).
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* preload_manifest?: bool|Param, // Preload the PWA manifest file. // Default: true
|
||||
* preload_serviceworker?: bool|Param, // Preload the service worker script. Disabled by default as SW registration is usually deferred. // Default: false
|
||||
* preconnect_workbox_cdn?: bool|Param, // Preconnect to Workbox CDN when using CDN mode. // Default: true
|
||||
* },
|
||||
* favicons?: bool|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* default?: array{ // The favicon source and parameters. When used with "dark", this favicon will become the light version.
|
||||
* src?: scalar|Param|null, // The path to the icon. Can be served by Asset Mapper, an absolute path or a Symfony UX Icon (if the bundle is installed).
|
||||
* background_color?: scalar|Param|null, // The background color of the application. If this value is not defined and that of the Manifest section is, the value of the latter will be used. // Default: null
|
||||
* border_radius?: int|Param, // The border radius of the icon. // Default: null
|
||||
* image_scale?: int|Param, // The scale of the icon. // Default: null
|
||||
* svg_attr?: array<string, mixed>,
|
||||
* },
|
||||
* dark?: array{ // The favicon source and parameters for the dark theme. Should only be used with "default".
|
||||
* src?: scalar|Param|null, // The path to the icon. Can be served by Asset Mapper, an absolute path or a Symfony UX Icon (if the bundle is installed).
|
||||
* background_color?: scalar|Param|null, // The background color of the application. If this value is not defined and that of the Manifest section is, the value of the latter will be used. // Default: null
|
||||
* border_radius?: int|Param, // The border radius of the icon. // Default: null
|
||||
* image_scale?: int|Param, // The scale of the icon. // Default: null
|
||||
* svg_attr?: array<string, mixed>,
|
||||
* },
|
||||
* src?: scalar|Param|null, // Deprecated: The "src" configuration key is deprecated. Use the "default.src" configuration key instead. // The source of the favicon. Shall be a SVG or large PNG. // Default: null
|
||||
* src_dark?: scalar|Param|null, // Deprecated: The "src_dark" configuration key is deprecated. Use the "dark.src" configuration key instead. // The source of the favicon in dark mode. Shall be a SVG or large PNG. // Default: null
|
||||
* background_color?: scalar|Param|null, // Deprecated: The "background_color" configuration key is deprecated. Use the "default.background_color" configuration key instead. // The background color of the icon. // Default: null
|
||||
* background_color_dark?: scalar|Param|null, // Deprecated: The "background_color_dark" configuration key is deprecated. Use the "dark.background_color" configuration key instead. // The background color of the icon in dark mode. // Default: null
|
||||
* safari_pinned_tab_color?: scalar|Param|null, // The color of the Safari pinned tab. Requires "use_silhouette" to be set to "true". // Default: null
|
||||
* tile_color?: scalar|Param|null, // The color of the tile for Windows 8+. // Default: null
|
||||
* border_radius?: int|Param, // Deprecated: The "border_radius" configuration key is deprecated. Use the "default.border_radius" or "dark.border_radius" configuration key instead. // The border radius of the icon. // Default: null
|
||||
* image_scale?: int|Param, // Deprecated: The "image_scale" configuration key is deprecated. Use the "default.image_scale" or "dark.image_scale" configuration key instead. // The scale of the icon. // Default: null
|
||||
* low_resolution?: bool|Param, // Include low resolution icons. // Default: false
|
||||
* use_silhouette?: bool|Param|null, // Use only the silhouette of the icon. Applicable for macOS Safari and Windows 8+. Requires potrace to be installed. // Default: null
|
||||
* use_start_image?: bool|Param, // Use the icon as a start image for the iOS splash screen. // Default: true
|
||||
* svg_color?: scalar|Param|null, // When the asset is a SVG file, replaces the currentColor attribute with this color. // Default: "#000"
|
||||
* monochrome?: bool|Param, // Use a monochrome icon. // Default: false
|
||||
* potrace?: scalar|Param|null, // The path to the potrace binary. // Default: "potrace"
|
||||
* },
|
||||
* image_processor?: scalar|Param|null, // The image processor to use to generate the icons of different sizes. // Default: null
|
||||
* logger?: scalar|Param|null, // The logger service to use. If not set, the default logger will be used. // Default: null
|
||||
* manifest?: bool|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* public_url?: scalar|Param|null, // The public URL of the manifest file. // Default: "/site.webmanifest"
|
||||
* use_credentials?: bool|Param, // Indicates whether the manifest should be fetched with credentials. // Default: true
|
||||
* background_color?: scalar|Param|null, // The background color of the application. It should match the background-color CSS property in the sites stylesheet for a smooth transition between launching the web application and loading the site's content.
|
||||
* categories?: list<scalar|Param|null>,
|
||||
* description?: scalar|Param|null, // The description of the application.
|
||||
* display?: scalar|Param|null, // The display mode of the application.
|
||||
* display_override?: list<scalar|Param|null>,
|
||||
* id?: scalar|Param|null, // A string that represents the identity of the web application.
|
||||
* orientation?: scalar|Param|null, // The orientation of the application.
|
||||
* dir?: scalar|Param|null, // The direction of the application.
|
||||
* lang?: scalar|Param|null, // The language of the application.
|
||||
* name?: scalar|Param|null, // The name of the application.
|
||||
* short_name?: scalar|Param|null, // The short name of the application.
|
||||
* scope?: scalar|Param|null, // The scope of the application.
|
||||
* start_url?: string|array{ // The start URL of the application.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* theme_color?: scalar|Param|null, // The theme color of the application. If a dark theme color is specified, the theme color will be used for the light theme.
|
||||
* dark_theme_color?: scalar|Param|null, // The dark theme color of the application.
|
||||
* edge_side_panel?: array{ // Specifies whether or not your app supports the side panel view in Microsoft Edge.
|
||||
* preferred_width?: int|Param, // Specifies the preferred width of the side panel view in Microsoft Edge.
|
||||
* },
|
||||
* iarc_rating_id?: scalar|Param|null, // Specifies the International Age Rating Coalition (IARC) rating ID for the app. See https://www.globalratings.com/how-iarc-works.aspx for more information.
|
||||
* scope_extensions?: list<array{ // Default: []
|
||||
* type?: scalar|Param|null, // Specifies the type of scope extension. This is currently always origin (default), but future extensions may add other types. // Default: "origin"
|
||||
* origin?: scalar|Param|null, // Specifies the origin pattern to associate with.
|
||||
* }>,
|
||||
* handle_links?: scalar|Param|null, // Specifies the default link handling for the web app.
|
||||
* note_taking?: array{ // The note-taking capabilities of the application.
|
||||
* note_taking_url?: string|array{ // The URL to the note-taking service.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* },
|
||||
* icons?: list<string|array{ // Default: []
|
||||
* src?: scalar|Param|null, // The path to the icon. Can be served by Asset Mapper, an absolute path or a Symfony UX Icon (if the bundle is installed).
|
||||
* sizes?: list<int|Param>,
|
||||
* background_color?: scalar|Param|null, // The background color of the application. If this value is not defined and that of the Manifest section is, the value of the latter will be used. // Default: null
|
||||
* border_radius?: int|Param, // The border radius of the icon. // Default: null
|
||||
* image_scale?: int|Param, // The scale of the icon. // Default: null
|
||||
* type?: scalar|Param|null, // The icon mime type.
|
||||
* format?: scalar|Param|null, // The icon format. When set, the "type" option is ignored and the image will be converted.
|
||||
* purpose?: scalar|Param|null, // The purpose of the icon.
|
||||
* svg_attr?: array<string, mixed>,
|
||||
* }>,
|
||||
* screenshots?: list<string|array{ // Default: []
|
||||
* src?: scalar|Param|null, // The path to the screenshot. Can be served by Asset Mapper.
|
||||
* height?: scalar|Param|null, // Default: null
|
||||
* width?: scalar|Param|null, // Default: null
|
||||
* form_factor?: scalar|Param|null, // The form factor of the screenshot. Will guess the form factor if not set.
|
||||
* label?: scalar|Param|null, // The label of the screenshot.
|
||||
* platform?: scalar|Param|null, // The platform of the screenshot.
|
||||
* format?: scalar|Param|null, // The format of the screenshot. Will convert the file if set.
|
||||
* reference?: scalar|Param|null, // The URL of the screenshot. Only for reference and not used by the bundle. // Default: null
|
||||
* }>,
|
||||
* file_handlers?: list<array{ // Default: []
|
||||
* action?: string|array{ // The action to take.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* accept?: array<string, list<scalar|Param|null>>,
|
||||
* }>,
|
||||
* launch_handler?: array{ // The launch handler of the application.
|
||||
* client_mode?: list<scalar|Param|null>,
|
||||
* },
|
||||
* protocol_handlers?: list<array{ // Default: []
|
||||
* protocol?: scalar|Param|null, // The protocol of the handler.
|
||||
* placeholder?: scalar|Param|null, // The placeholder of the handler. Will be replaced by "xxx=%s". // Default: null
|
||||
* url?: string|array{ // The URL of the handler.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* }>,
|
||||
* prefer_related_applications?: bool|Param, // prefer related native applications (instead of this application) // Default: false
|
||||
* related_applications?: list<array{ // Default: []
|
||||
* platform?: scalar|Param|null, // The platform of the application.
|
||||
* url?: string|array{ // The URL of the application.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* id?: scalar|Param|null, // The ID of the application.
|
||||
* }>,
|
||||
* shortcuts?: list<array{ // Default: []
|
||||
* name?: scalar|Param|null, // The name of the shortcut.
|
||||
* short_name?: scalar|Param|null, // The short name of the shortcut.
|
||||
* description?: scalar|Param|null, // The description of the shortcut.
|
||||
* url?: string|array{ // The URL of the shortcut.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* icons?: list<string|array{ // Default: []
|
||||
* src?: scalar|Param|null, // The path to the icon. Can be served by Asset Mapper, an absolute path or a Symfony UX Icon (if the bundle is installed).
|
||||
* sizes?: list<int|Param>,
|
||||
* background_color?: scalar|Param|null, // The background color of the application. If this value is not defined and that of the Manifest section is, the value of the latter will be used. // Default: null
|
||||
* border_radius?: int|Param, // The border radius of the icon. // Default: null
|
||||
* image_scale?: int|Param, // The scale of the icon. // Default: null
|
||||
* type?: scalar|Param|null, // The icon mime type.
|
||||
* format?: scalar|Param|null, // The icon format. When set, the "type" option is ignored and the image will be converted.
|
||||
* purpose?: scalar|Param|null, // The purpose of the icon.
|
||||
* svg_attr?: array<string, mixed>,
|
||||
* }>,
|
||||
* }>,
|
||||
* share_target?: array{ // The share target of the application.
|
||||
* action?: string|array{ // The action of the share target.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* method?: scalar|Param|null, // The method of the share target.
|
||||
* enctype?: scalar|Param|null, // The enctype of the share target. Ignored if method is GET.
|
||||
* params?: array{ // The parameters of the share target.
|
||||
* title?: scalar|Param|null, // The title of the share target.
|
||||
* text?: scalar|Param|null, // The text of the share target.
|
||||
* url?: scalar|Param|null, // The URL of the share target.
|
||||
* files?: list<array{ // Default: []
|
||||
* name?: scalar|Param|null, // The name of the file parameter.
|
||||
* accept?: list<scalar|Param|null>,
|
||||
* }>,
|
||||
* },
|
||||
* },
|
||||
* widgets?: list<array{ // Default: []
|
||||
* name?: scalar|Param|null, // The title of the widget, presented to users.
|
||||
* short_name?: scalar|Param|null, // An alternative short version of the name.
|
||||
* description?: scalar|Param|null, // The description of the widget.
|
||||
* icons?: list<string|array{ // Default: []
|
||||
* src?: scalar|Param|null, // The path to the icon. Can be served by Asset Mapper, an absolute path or a Symfony UX Icon (if the bundle is installed).
|
||||
* sizes?: list<int|Param>,
|
||||
* background_color?: scalar|Param|null, // The background color of the application. If this value is not defined and that of the Manifest section is, the value of the latter will be used. // Default: null
|
||||
* border_radius?: int|Param, // The border radius of the icon. // Default: null
|
||||
* image_scale?: int|Param, // The scale of the icon. // Default: null
|
||||
* type?: scalar|Param|null, // The icon mime type.
|
||||
* format?: scalar|Param|null, // The icon format. When set, the "type" option is ignored and the image will be converted.
|
||||
* purpose?: scalar|Param|null, // The purpose of the icon.
|
||||
* svg_attr?: array<string, mixed>,
|
||||
* }>,
|
||||
* screenshots?: list<string|array{ // Default: []
|
||||
* src?: scalar|Param|null, // The path to the screenshot. Can be served by Asset Mapper.
|
||||
* height?: scalar|Param|null, // Default: null
|
||||
* width?: scalar|Param|null, // Default: null
|
||||
* form_factor?: scalar|Param|null, // The form factor of the screenshot. Will guess the form factor if not set.
|
||||
* label?: scalar|Param|null, // The label of the screenshot.
|
||||
* platform?: scalar|Param|null, // The platform of the screenshot.
|
||||
* format?: scalar|Param|null, // The format of the screenshot. Will convert the file if set.
|
||||
* reference?: scalar|Param|null, // The URL of the screenshot. Only for reference and not used by the bundle. // Default: null
|
||||
* }>,
|
||||
* tag?: scalar|Param|null, // A string used to reference the widget in the PWA service worker.
|
||||
* template?: scalar|Param|null, // The template to use to display the widget in the operating system widgets dashboard. Note: this property is currently only informational and not used. See ms_ac_template below.
|
||||
* ms_ac_template?: string|array{ // The URL of the custom Adaptive Cards template to use to display the widget in the operating system widgets dashboard.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* data?: string|array{ // The URL where the data to fill the template with can be found. If present, this URL is required to return valid JSON.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* type?: scalar|Param|null, // The MIME type for the widget data.
|
||||
* auth?: bool|Param, // A boolean indicating if the widget requires authentication.
|
||||
* update?: int|Param, // The frequency, in seconds, at which the widget will be updated. Code in your service worker must perform the updating; the widget is not updated automatically. See Access widget instances at runtime.
|
||||
* multiple?: bool|Param, // A boolean indicating whether to allow multiple instances of the widget. Defaults to true. // Default: true
|
||||
* }>,
|
||||
* },
|
||||
* path_type_reference?: int|Param, // Deprecated: The "path_type_reference" configuration key is deprecated. Use the "path_type_reference" of URL nodes instead. // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* resource_hints?: bool|array{ // Resource Hints configuration for preconnect, dns-prefetch, and preload.
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* auto_preconnect?: bool|Param, // Automatically add preconnect hints for detected external origins (Workbox CDN, Google Fonts). // Default: true
|
||||
* preconnect?: list<scalar|Param|null>,
|
||||
* dns_prefetch?: list<scalar|Param|null>,
|
||||
* preload?: list<array{ // Default: []
|
||||
* href?: scalar|Param|null, // The URL or path to preload.
|
||||
* as?: "script"|"style"|"font"|"image"|"fetch"|"document"|"audio"|"video"|"track"|"worker"|Param, // The resource type.
|
||||
* type?: scalar|Param|null, // The MIME type of the resource. // Default: null
|
||||
* crossorigin?: "anonymous"|"use-credentials"|Param, // The crossorigin attribute value. Required for fonts. // Default: null
|
||||
* fetchpriority?: "high"|"low"|"auto"|Param, // The fetch priority hint. // Default: null
|
||||
* media?: scalar|Param|null, // Media query for responsive preloading. // Default: null
|
||||
* }>,
|
||||
* },
|
||||
* serviceworker?: bool|string|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* src?: scalar|Param|null, // The path to the service worker source file. Can be served by Asset Mapper.
|
||||
* dest?: scalar|Param|null, // The public URL to the service worker. // Default: "/sw.js"
|
||||
* skip_waiting?: bool|Param, // Whether to skip waiting for the service worker to be activated. // Default: false
|
||||
* scope?: scalar|Param|null, // The scope of the service worker. // Default: "/"
|
||||
* use_cache?: bool|Param, // Whether the service worker should use the cache. // Default: true
|
||||
* workbox?: bool|array{ // The configuration of the workbox.
|
||||
* enabled?: bool|Param, // Default: true
|
||||
* use_cdn?: bool|Param, // Deprecated: The "use_cdn" option is deprecated and will be removed in 2.0.0. use "config.use_cdn" instead. // Whether to use the local workbox or the CDN. // Default: false
|
||||
* google_fonts?: bool|array{
|
||||
* enabled?: bool|Param, // Default: true
|
||||
* cache_prefix?: scalar|Param|null, // The cache prefix for the Google fonts. // Default: null
|
||||
* max_age?: scalar|Param|null, // The maximum age of the Google fonts cache (in seconds). // Default: null
|
||||
* max_entries?: int|Param, // The maximum number of entries in the Google fonts cache. // Default: null
|
||||
* },
|
||||
* cache_manifest?: bool|Param, // Whether to cache the manifest file. // Default: true
|
||||
* version?: scalar|Param|null, // Deprecated: The "version" option is deprecated and will be removed in 2.0.0. use "config.version" instead. // The version of workbox. When using local files, the version shall be "7.0.0." // Default: "7.3.0"
|
||||
* workbox_public_url?: scalar|Param|null, // Deprecated: The "workbox_public_url" option is deprecated and will be removed in 2.0.0. use "config.workbox_public_url" instead. // The public path to the local workbox. Only used if use_cdn is false. // Default: "/workbox"
|
||||
* idb_public_url?: scalar|Param|null, // The public path to the local IndexDB. Only used if use_cdn is false. // Default: "/idb"
|
||||
* workbox_import_placeholder?: scalar|Param|null, // Deprecated: The "workbox_import_placeholder" option is deprecated and will be removed in 2.0.0. No replacement. // The placeholder for the workbox import. Will be replaced by the workbox import. // Default: "//WORKBOX_IMPORT_PLACEHOLDER"
|
||||
* standard_rules_placeholder?: scalar|Param|null, // Deprecated: The "standard_rules_placeholder" option is deprecated and will be removed in 2.0.0. No replacement. // The placeholder for the standard rules. Will be replaced by caching strategies. // Default: "//STANDARD_RULES_PLACEHOLDER"
|
||||
* offline_fallback_placeholder?: scalar|Param|null, // Deprecated: The "offline_fallback_placeholder" option is deprecated and will be removed in 2.0.0. No replacement. // The placeholder for the offline fallback. Will be replaced by the URL. // Default: "//OFFLINE_FALLBACK_PLACEHOLDER"
|
||||
* widgets_placeholder?: scalar|Param|null, // Deprecated: The "widgets_placeholder" option is deprecated and will be removed in 2.0.0. No replacement. // The placeholder for the widgets. Will be replaced by the widgets management events. // Default: "//WIDGETS_PLACEHOLDER"
|
||||
* clear_cache?: bool|Param, // Whether to clear the cache during the service worker activation. // Default: true
|
||||
* navigation_preload?: bool|Param, // Whether to enable navigation preload. This speeds up navigation requests by making the network request in parallel with service worker boot-up. Note: Do not enable if you are precaching HTML pages (e.g., with offline_fallback or warm_cache_urls), as it would be redundant. // Default: false
|
||||
* config?: array{
|
||||
* debug?: bool|Param, // Controls workbox debug logging. Set to false to disable debug mode and logging. // Default: true
|
||||
* version?: scalar|Param|null, // The version of workbox. When using local files, the version shall be "7.0.0." // Default: "7.3.0"
|
||||
* use_cdn?: bool|Param, // Whether to use the local workbox or the CDN. // Default: false
|
||||
* workbox_public_url?: scalar|Param|null, // The public path to the local workbox. Only used if use_cdn is false. // Default: "/workbox"
|
||||
* },
|
||||
* offline_fallback?: array{
|
||||
* cache_name?: scalar|Param|null, // The name of the offline cache. // Default: "offline"
|
||||
* page?: string|array{ // The URL of the offline page fallback.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* image?: string|array{ // The URL of the offline image fallback.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* font?: string|array{ // The URL of the offline font fallback.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* },
|
||||
* image_cache?: bool|array{
|
||||
* enabled?: bool|Param, // Default: true
|
||||
* cache_name?: scalar|Param|null, // The name of the image cache. // Default: "images"
|
||||
* regex?: scalar|Param|null, // The regex to match the images. // Default: "/\\.(ico|png|jpe?g|gif|svg|webp|bmp)$/"
|
||||
* max_entries?: int|Param, // The maximum number of entries in the image cache. // Default: 60
|
||||
* max_age?: scalar|Param|null, // The maximum number of seconds before the image cache is invalidated. // Default: 31536000
|
||||
* },
|
||||
* asset_cache?: bool|array{
|
||||
* enabled?: bool|Param, // Default: true
|
||||
* cache_name?: scalar|Param|null, // The name of the asset cache. // Default: "assets"
|
||||
* regex?: scalar|Param|null, // The regex to match the assets. // Default: "/\\.(css|js|json|xml|txt|map|ico|png|jpe?g|gif|svg|webp|bmp)$/"
|
||||
* max_age?: scalar|Param|null, // The maximum number of seconds before the asset cache is invalidated. // Default: 31536000
|
||||
* },
|
||||
* font_cache?: bool|array{
|
||||
* enabled?: bool|Param, // Default: true
|
||||
* cache_name?: scalar|Param|null, // The name of the font cache. // Default: "fonts"
|
||||
* regex?: scalar|Param|null, // The regex to match the fonts. // Default: "/\\.(ttf|eot|otf|woff2)$/"
|
||||
* max_entries?: int|Param, // The maximum number of entries in the image cache. // Default: 60
|
||||
* max_age?: int|Param, // The maximum number of seconds before the font cache is invalidated. // Default: 31536000
|
||||
* },
|
||||
* resource_caches?: list<array{ // Default: []
|
||||
* match_callback?: scalar|Param|null, // The regex or callback function to match the URLs.
|
||||
* cache_name?: scalar|Param|null, // The name of the page cache.
|
||||
* network_timeout?: int|Param, // The network timeout in seconds before cache is called (for "NetworkFirst" and "NetworkOnly" strategies). // Default: 3
|
||||
* strategy?: scalar|Param|null, // The caching strategy. Only "NetworkFirst", "CacheFirst" and "StaleWhileRevalidate" are supported. StaleWhileRevalidate provides instant page loads with background updates. // Default: "StaleWhileRevalidate"
|
||||
* max_entries?: scalar|Param|null, // The maximum number of entries in the cache (for "CacheFirst" and "NetworkFirst" strategy only). // Default: null
|
||||
* max_age?: scalar|Param|null, // The maximum number of seconds before the cache is invalidated (for "CacheFirst" and "NetWorkFirst" strategy only). // Default: null
|
||||
* broadcast?: bool|Param, // Whether to broadcast the cache update events (for "StaleWhileRevalidate" strategy only). Enables client notification when content is updated. // Default: true
|
||||
* range_requests?: bool|Param, // Whether to support range requests (for "CacheFirst" strategy only). // Default: false
|
||||
* cacheable_response_headers?: list<scalar|Param|null>,
|
||||
* cacheable_response_statuses?: list<int|Param>,
|
||||
* broadcast_headers?: list<scalar|Param|null>,
|
||||
* preload_urls?: list<string|array{ // Default: []
|
||||
* path?: scalar|Param|null, // The URL of the shortcut.
|
||||
* params?: list<mixed>,
|
||||
* }>,
|
||||
* }>,
|
||||
* background_sync?: list<array{ // Default: []
|
||||
* queue_name?: scalar|Param|null, // The name of the queue.
|
||||
* match_callback?: scalar|Param|null, // The regex or callback function to match the URLs.
|
||||
* error_on_4xx?: bool|Param, // Whether to retry the request on 4xx errors. // Default: true
|
||||
* error_on_5xx?: bool|Param, // Whether to retry the request on 5xx errors. // Default: true
|
||||
* expected_status_codes?: list<int|Param>,
|
||||
* expect_redirect?: bool|Param, // Whether to expect a redirect (JS response type should be "opaqueredirect" or the "redirected" property is "true"). // Default: false
|
||||
* method?: scalar|Param|null, // The HTTP method. // Default: "POST"
|
||||
* broadcast_channel?: scalar|Param|null, // The broadcast channel. Set null to disable. // Default: null
|
||||
* max_retention_time?: int|Param, // The maximum retention time in minutes. // Default: 1440
|
||||
* force_sync_fallback?: bool|Param, // If `true`, instead of attempting to use background sync events, always attempt to replay queued request at service worker startup. Most folks will not need this, unless you explicitly target a runtime like Electron that exposes the interfaces for background sync, but does not have a working implementation. // Default: false
|
||||
* }>,
|
||||
* background_fetch?: bool|array{
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* db_name?: scalar|Param|null, // The IndexDB name where downloads are stored // Default: "bgfetch-completed"
|
||||
* progress_url?: string|array{ // The URL of the progress page.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* success_url?: string|array{ // The URL of the success page.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* success_message?: scalar|Param|null, // The message to display on success. This message is translated. // Default: null
|
||||
* failure_message?: scalar|Param|null, // The message to display on success. This message is translated. // Default: null
|
||||
* },
|
||||
* image_cache_name?: scalar|Param|null, // Deprecated: The "image_cache_name" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.image_cache.cache_name" instead. // The name of the image cache. // Default: "images"
|
||||
* font_cache_name?: scalar|Param|null, // Deprecated: The "font_cache_name" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.font_cache.cache_name" instead. // The name of the font cache. // Default: "fonts"
|
||||
* page_cache_name?: scalar|Param|null, // Deprecated: The "page_cache_name" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.resource_caches[].cache_name" instead. // The name of the page cache. // Default: "pages"
|
||||
* asset_cache_name?: scalar|Param|null, // Deprecated: The "asset_cache_name" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.asset_cache.cache_name" instead. // The name of the asset cache. // Default: "assets"
|
||||
* page_fallback?: string|array{ // The URL of the offline page fallback.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* image_fallback?: string|array{ // The URL of the offline image fallback.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* font_fallback?: string|array{ // The URL of the offline font fallback.
|
||||
* path?: scalar|Param|null, // The URL or route name.
|
||||
* path_type_reference?: int|Param, // The path type reference to generate paths/URLs. See https://symfony.com/doc/current/routing.html#generating-urls-in-controllers for more information. // Default: 1
|
||||
* params?: list<mixed>,
|
||||
* },
|
||||
* image_regex?: scalar|Param|null, // Deprecated: The "image_regex" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.image_cache.regex" instead. // The regex to match the images. // Default: "/\\.(ico|png|jpe?g|gif|svg|webp|bmp)$/"
|
||||
* static_regex?: scalar|Param|null, // Deprecated: The "static_regex" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.asset_cache.regex" instead. // The regex to match the static files. // Default: "/\\.(css|js|json|xml|txt|map)$/"
|
||||
* font_regex?: scalar|Param|null, // Deprecated: The "font_regex" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.font_cache.regex" instead. // The regex to match the static files. // Default: "/\\.(ttf|eot|otf|woff2)$/"
|
||||
* max_image_cache_entries?: int|Param, // Deprecated: The "max_image_cache_entries" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.image_cache.max_entries" instead. // The maximum number of entries in the image cache. // Default: 60
|
||||
* max_image_age?: int|Param, // Deprecated: The "max_image_age" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.image_cache.max_age" instead. // The maximum number of seconds before the image cache is invalidated. // Default: 31536000
|
||||
* max_font_cache_entries?: int|Param, // Deprecated: The "max_font_cache_entries" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.font_cache.max_entries" instead. // The maximum number of entries in the font cache. // Default: 30
|
||||
* max_font_age?: int|Param, // Deprecated: The "max_font_age" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.font_cache.max_age" instead. // The maximum number of seconds before the font cache is invalidated. // Default: 31536000
|
||||
* network_timeout_seconds?: int|Param, // Deprecated: The "network_timeout_seconds" option is deprecated and will be removed in 2.0.0. Please use "pwa.serviceworker.workbox.resource_caches[].network_timeout" instead. // The network timeout in seconds before cache is called (for warm cache URLs only). // Default: 3
|
||||
* warm_cache_urls?: list<string|array{ // Default: []
|
||||
* path?: scalar|Param|null, // The URL of the shortcut.
|
||||
* params?: list<mixed>,
|
||||
* }>,
|
||||
* },
|
||||
* },
|
||||
* speculation_rules?: bool|array{ // Speculation Rules API configuration for prefetching and prerendering pages.
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* prefetch?: list<array{ // Default: []
|
||||
* source?: "list"|"document"|Param, // The source type: "list" for explicit URLs, "document" for link matching. // Default: "document"
|
||||
* urls?: list<string|array{ // Default: []
|
||||
* path?: scalar|Param|null, // The URL path or route name.
|
||||
* params?: list<mixed>,
|
||||
* }>,
|
||||
* selector_matches?: scalar|Param|null, // For "document" source: CSS selector to match links. // Default: null
|
||||
* href_matches?: scalar|Param|null, // For "document" source: URL pattern to match href attributes. // Default: null
|
||||
* eagerness?: "immediate"|"eager"|"moderate"|"conservative"|Param, // Eagerness level: "immediate" (viewport), "eager" (hover 200ms), "moderate" (hover 100ms), "conservative" (mousedown/touchstart). // Default: "moderate"
|
||||
* referrer_policy?: scalar|Param|null, // Referrer policy for the speculative request. // Default: null
|
||||
* }>,
|
||||
* prerender?: list<array{ // Default: []
|
||||
* source?: "list"|"document"|Param, // The source type: "list" for explicit URLs, "document" for link matching. // Default: "document"
|
||||
* urls?: list<string|array{ // Default: []
|
||||
* path?: scalar|Param|null, // The URL path or route name.
|
||||
* params?: list<mixed>,
|
||||
* }>,
|
||||
* selector_matches?: scalar|Param|null, // For "document" source: CSS selector to match links. // Default: null
|
||||
* href_matches?: scalar|Param|null, // For "document" source: URL pattern to match href attributes. // Default: null
|
||||
* eagerness?: "immediate"|"eager"|"moderate"|"conservative"|Param, // Eagerness level. For prerender, "conservative" is recommended. // Default: "conservative"
|
||||
* referrer_policy?: scalar|Param|null, // Referrer policy for the speculative request. // Default: null
|
||||
* }>,
|
||||
* },
|
||||
* web_client?: scalar|Param|null, // The Panther Client for generating screenshots. If not set, the default client will be used. // Default: null
|
||||
* user_agent?: scalar|Param|null, // The user agent to use when generating screenshots. When this user agent is detected, the Symfony profiler and debug toolbar will be automatically disabled to ensure screenshots look like production. // Default: "PWAScreenshotBot"
|
||||
* }
|
||||
* @psalm-type VichUploaderConfig = array{
|
||||
* default_filename_attribute_suffix?: scalar|Param|null, // Default: "_name"
|
||||
* db_driver?: scalar|Param|null,
|
||||
* storage?: scalar|Param|null, // Default: "file_system"
|
||||
* use_flysystem_to_resolve_uri?: bool|Param, // Default: false
|
||||
* twig?: scalar|Param|null, // twig requires templating // Default: true
|
||||
* form?: scalar|Param|null, // Default: true
|
||||
* metadata?: array{
|
||||
* cache?: scalar|Param|null, // Default: "file"
|
||||
* type?: scalar|Param|null, // Default: "attribute"
|
||||
* file_cache?: array{
|
||||
* dir?: scalar|Param|null, // Default: "%kernel.cache_dir%/vich_uploader"
|
||||
* },
|
||||
* auto_detection?: bool|Param, // Default: true
|
||||
* directories?: list<array{ // Default: []
|
||||
* path?: scalar|Param|null,
|
||||
* namespace_prefix?: scalar|Param|null, // Default: ""
|
||||
* }>,
|
||||
* },
|
||||
* mappings?: array<string, array{ // Default: []
|
||||
* uri_prefix?: scalar|Param|null, // Default: "/uploads"
|
||||
* upload_destination?: scalar|Param|null, // Default: null
|
||||
* namer?: string|array{
|
||||
* service?: scalar|Param|null, // Default: null
|
||||
* options?: mixed, // Default: null
|
||||
* },
|
||||
* directory_namer?: string|array{
|
||||
* service?: scalar|Param|null, // Default: null
|
||||
* options?: mixed, // Default: null
|
||||
* },
|
||||
* delete_on_remove?: scalar|Param|null, // Default: true
|
||||
* erase_fields?: scalar|Param|null, // Default: true
|
||||
* delete_on_update?: scalar|Param|null, // Default: true
|
||||
* inject_on_load?: scalar|Param|null, // Default: false
|
||||
* namer_keep_extension?: scalar|Param|null, // Default: false
|
||||
* db_driver?: scalar|Param|null, // Default: null
|
||||
* }>,
|
||||
* }
|
||||
* @psalm-type SchebTwoFactorConfig = array{
|
||||
* persister?: scalar|Param|null, // Default: "scheb_two_factor.persister.doctrine"
|
||||
* model_manager_name?: scalar|Param|null, // Default: null
|
||||
* security_tokens?: list<scalar|Param|null>,
|
||||
* ip_whitelist?: list<scalar|Param|null>,
|
||||
* ip_whitelist_provider?: scalar|Param|null, // Default: "scheb_two_factor.default_ip_whitelist_provider"
|
||||
* two_factor_token_factory?: scalar|Param|null, // Default: "scheb_two_factor.default_token_factory"
|
||||
* two_factor_provider_decider?: scalar|Param|null, // Default: "scheb_two_factor.default_provider_decider"
|
||||
* two_factor_condition?: scalar|Param|null, // Default: null
|
||||
* code_reuse_cache?: scalar|Param|null, // Default: null
|
||||
* code_reuse_cache_duration?: int|Param, // Default: 60
|
||||
* code_reuse_default_handler?: scalar|Param|null, // Default: null
|
||||
* backup_codes?: bool|array{
|
||||
* enabled?: scalar|Param|null, // Default: false
|
||||
* manager?: scalar|Param|null, // Default: "scheb_two_factor.default_backup_code_manager"
|
||||
* },
|
||||
* email?: bool|array{
|
||||
* enabled?: scalar|Param|null, // Default: false
|
||||
* mailer?: scalar|Param|null, // Default: null
|
||||
* code_generator?: scalar|Param|null, // Default: "scheb_two_factor.security.email.default_code_generator"
|
||||
* form_renderer?: scalar|Param|null, // Default: null
|
||||
* sender_email?: scalar|Param|null, // Default: null
|
||||
* sender_name?: scalar|Param|null, // Default: null
|
||||
* template?: scalar|Param|null, // Default: "@SchebTwoFactor/Authentication/form.html.twig"
|
||||
* digits?: int|Param, // Default: 4
|
||||
* },
|
||||
* google?: bool|array{
|
||||
* enabled?: scalar|Param|null, // Default: false
|
||||
* form_renderer?: scalar|Param|null, // Default: null
|
||||
* issuer?: scalar|Param|null, // Default: null
|
||||
* server_name?: scalar|Param|null, // Default: null
|
||||
* template?: scalar|Param|null, // Default: "@SchebTwoFactor/Authentication/form.html.twig"
|
||||
* digits?: int|Param, // Default: 6
|
||||
* leeway?: int|Param, // Default: 0
|
||||
* },
|
||||
* }
|
||||
* @psalm-type ConfigType = array{
|
||||
* imports?: ImportsConfig,
|
||||
* parameters?: ParametersConfig,
|
||||
@@ -1463,11 +2283,18 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* doctrine?: DoctrineConfig,
|
||||
* doctrine_migrations?: DoctrineMigrationsConfig,
|
||||
* twig?: TwigConfig,
|
||||
* stimulus?: StimulusConfig,
|
||||
* turbo?: TurboConfig,
|
||||
* twig_extra?: TwigExtraConfig,
|
||||
* security?: SecurityConfig,
|
||||
* monolog?: MonologConfig,
|
||||
* endroid_qr_code?: EndroidQrCodeConfig,
|
||||
* knp_paginator?: KnpPaginatorConfig,
|
||||
* knpu_oauth2_client?: KnpuOauth2ClientConfig,
|
||||
* flysystem?: FlysystemConfig,
|
||||
* liip_imagine?: LiipImagineConfig,
|
||||
* nelmio_security?: NelmioSecurityConfig,
|
||||
* pwa?: PwaConfig,
|
||||
* vich_uploader?: VichUploaderConfig,
|
||||
* scheb_two_factor?: SchebTwoFactorConfig,
|
||||
* "when@dev"?: array{
|
||||
* imports?: ImportsConfig,
|
||||
* parameters?: ParametersConfig,
|
||||
@@ -1478,12 +2305,19 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* debug?: DebugConfig,
|
||||
* twig?: TwigConfig,
|
||||
* web_profiler?: WebProfilerConfig,
|
||||
* stimulus?: StimulusConfig,
|
||||
* turbo?: TurboConfig,
|
||||
* twig_extra?: TwigExtraConfig,
|
||||
* security?: SecurityConfig,
|
||||
* monolog?: MonologConfig,
|
||||
* maker?: MakerConfig,
|
||||
* endroid_qr_code?: EndroidQrCodeConfig,
|
||||
* knp_paginator?: KnpPaginatorConfig,
|
||||
* knpu_oauth2_client?: KnpuOauth2ClientConfig,
|
||||
* flysystem?: FlysystemConfig,
|
||||
* liip_imagine?: LiipImagineConfig,
|
||||
* nelmio_security?: NelmioSecurityConfig,
|
||||
* pwa?: PwaConfig,
|
||||
* vich_uploader?: VichUploaderConfig,
|
||||
* scheb_two_factor?: SchebTwoFactorConfig,
|
||||
* },
|
||||
* "when@prod"?: array{
|
||||
* imports?: ImportsConfig,
|
||||
@@ -1493,11 +2327,18 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* doctrine?: DoctrineConfig,
|
||||
* doctrine_migrations?: DoctrineMigrationsConfig,
|
||||
* twig?: TwigConfig,
|
||||
* stimulus?: StimulusConfig,
|
||||
* turbo?: TurboConfig,
|
||||
* twig_extra?: TwigExtraConfig,
|
||||
* security?: SecurityConfig,
|
||||
* monolog?: MonologConfig,
|
||||
* endroid_qr_code?: EndroidQrCodeConfig,
|
||||
* knp_paginator?: KnpPaginatorConfig,
|
||||
* knpu_oauth2_client?: KnpuOauth2ClientConfig,
|
||||
* flysystem?: FlysystemConfig,
|
||||
* liip_imagine?: LiipImagineConfig,
|
||||
* nelmio_security?: NelmioSecurityConfig,
|
||||
* pwa?: PwaConfig,
|
||||
* vich_uploader?: VichUploaderConfig,
|
||||
* scheb_two_factor?: SchebTwoFactorConfig,
|
||||
* },
|
||||
* "when@test"?: array{
|
||||
* imports?: ImportsConfig,
|
||||
@@ -1508,11 +2349,18 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* doctrine_migrations?: DoctrineMigrationsConfig,
|
||||
* twig?: TwigConfig,
|
||||
* web_profiler?: WebProfilerConfig,
|
||||
* stimulus?: StimulusConfig,
|
||||
* turbo?: TurboConfig,
|
||||
* twig_extra?: TwigExtraConfig,
|
||||
* security?: SecurityConfig,
|
||||
* monolog?: MonologConfig,
|
||||
* endroid_qr_code?: EndroidQrCodeConfig,
|
||||
* knp_paginator?: KnpPaginatorConfig,
|
||||
* knpu_oauth2_client?: KnpuOauth2ClientConfig,
|
||||
* flysystem?: FlysystemConfig,
|
||||
* liip_imagine?: LiipImagineConfig,
|
||||
* nelmio_security?: NelmioSecurityConfig,
|
||||
* pwa?: PwaConfig,
|
||||
* vich_uploader?: VichUploaderConfig,
|
||||
* scheb_two_factor?: SchebTwoFactorConfig,
|
||||
* },
|
||||
* ...<string, ExtensionType|array{ // extra keys must follow the when@%env% pattern or match an extension alias
|
||||
* imports?: ImportsConfig,
|
||||
|
||||
2
config/routes/liip_imagine.yaml
Normal file
2
config/routes/liip_imagine.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
_liip_imagine:
|
||||
resource: "@LiipImagineBundle/Resources/config/routing.yaml"
|
||||
7
config/routes/scheb_2fa.yaml
Normal file
7
config/routes/scheb_2fa.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
2fa_login:
|
||||
path: /2fa
|
||||
defaults:
|
||||
_controller: "scheb_two_factor.form_controller::form"
|
||||
|
||||
2fa_login_check:
|
||||
path: /2fa_check
|
||||
@@ -7,6 +7,7 @@
|
||||
# Put parameters here that don't need to change on each machine where the app is deployed
|
||||
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
||||
parameters:
|
||||
admin_email: '%env(ADMIN_EMAIL)%'
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
@@ -19,5 +20,6 @@ services:
|
||||
App\:
|
||||
resource: '../src/'
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
App\Twig\ViteAssetExtension:
|
||||
arguments:
|
||||
$manifest: '%kernel.project_dir%/public/build/.vite/manifest.json'
|
||||
|
||||
193
docker-compose-dev.yml
Normal file
193
docker-compose-dev.yml
Normal file
@@ -0,0 +1,193 @@
|
||||
services:
|
||||
php:
|
||||
build:
|
||||
context: ./docker/php/dev
|
||||
dockerfile: Dockerfile
|
||||
container_name: crm_ecosplay_php
|
||||
restart: unless-stopped
|
||||
group_add:
|
||||
- "${DOCKER_GID:-989}"
|
||||
volumes:
|
||||
- .:/app
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
ports:
|
||||
- "9000:9000"
|
||||
depends_on:
|
||||
pgbouncer:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
|
||||
database:
|
||||
image: postgres:16-alpine
|
||||
container_name: crm_ecosplay_database
|
||||
environment:
|
||||
POSTGRES_USER: app
|
||||
POSTGRES_PASSWORD: secret
|
||||
POSTGRES_DB: crm_ecosplay
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U app -d crm_ecosplay"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
pgbouncer:
|
||||
image: edoburu/pgbouncer
|
||||
container_name: crm_ecosplay_pgbouncer
|
||||
volumes:
|
||||
- ./docker/pgsql/pgbouncer-dev.ini:/etc/pgbouncer/pgbouncer.ini:ro
|
||||
- ./docker/pgsql/userlist-dev.txt:/etc/pgbouncer/userlist.txt:ro
|
||||
ports:
|
||||
- "6432:6432"
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -p 6432 -U app"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: crm_ecosplay_redis
|
||||
command: redis-server --requirepass crm_ecosplay
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "crm_ecosplay", "ping"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
caddy:
|
||||
image: caddy:2-alpine
|
||||
container_name: crm_ecosplay_caddy
|
||||
ports:
|
||||
- "8000:80"
|
||||
volumes:
|
||||
- ./docker/caddy/Caddyfile:/etc/caddy/Caddyfile
|
||||
- .:/app
|
||||
depends_on:
|
||||
- php
|
||||
|
||||
messenger:
|
||||
build:
|
||||
context: ./docker/php/dev
|
||||
dockerfile: Dockerfile
|
||||
container_name: crm_ecosplay_messenger
|
||||
command: php bin/console messenger:consume async -vv
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- .:/app
|
||||
depends_on:
|
||||
pgbouncer:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
meilisearch:
|
||||
condition: service_started
|
||||
|
||||
bun:
|
||||
image: oven/bun:alpine
|
||||
container_name: crm_ecosplay_bun
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- .:/app
|
||||
- bun-modules:/app/node_modules
|
||||
command: sh -c "bun install && bun run dev"
|
||||
ports:
|
||||
- "5173:5173"
|
||||
|
||||
mailpit:
|
||||
image: axllent/mailpit
|
||||
container_name: crm_ecosplay_mailpit
|
||||
ports:
|
||||
- "1025:1025"
|
||||
- "8025:8025"
|
||||
|
||||
vault:
|
||||
image: hashicorp/vault:latest
|
||||
container_name: crm_ecosplay_vault
|
||||
cap_add:
|
||||
- IPC_LOCK
|
||||
environment:
|
||||
VAULT_DEV_ROOT_TOKEN_ID: crm_ecosplay
|
||||
VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200
|
||||
ports:
|
||||
- "8200:8200"
|
||||
volumes:
|
||||
- vault-data:/vault/file
|
||||
|
||||
ngrok:
|
||||
image: ngrok/ngrok:latest
|
||||
container_name: crm_ecosplay_ngrok
|
||||
command: http caddy:80 --log stdout
|
||||
environment:
|
||||
NGROK_AUTHTOKEN: GXtZtKtRxRF5TFV5pCKD_25f1ALUyQQ9LkyQJgv1dr
|
||||
ports:
|
||||
- "4040:4040"
|
||||
depends_on:
|
||||
- caddy
|
||||
|
||||
ngrok-sync:
|
||||
image: curlimages/curl:latest
|
||||
container_name: crm_ecosplay_ngrok_sync
|
||||
user: "0:0"
|
||||
volumes:
|
||||
- .:/app
|
||||
- ./docker/ngrok/sync.sh:/sync.sh
|
||||
depends_on:
|
||||
- ngrok
|
||||
entrypoint: sh /sync.sh
|
||||
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:latest
|
||||
container_name: crm_ecosplay_meilisearch
|
||||
environment:
|
||||
MEILI_MASTER_KEY: crm_ecosplay
|
||||
MEILI_ENV: development
|
||||
ports:
|
||||
- "7700:7700"
|
||||
volumes:
|
||||
- meilisearch-data:/meili_data
|
||||
|
||||
cron:
|
||||
build:
|
||||
context: ./docker/cron
|
||||
dockerfile: Dockerfile
|
||||
container_name: crm_ecosplay_cron
|
||||
restart: unless-stopped
|
||||
group_add:
|
||||
- "${DOCKER_GID:-989}"
|
||||
volumes:
|
||||
- .:/app
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
depends_on:
|
||||
pgbouncer:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
|
||||
redisinsight:
|
||||
image: redis/redisinsight:latest
|
||||
container_name: crm_ecosplay_redisinsight
|
||||
ports:
|
||||
- "5540:5540"
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
|
||||
volumes:
|
||||
db-data:
|
||||
redis-data:
|
||||
bun-modules:
|
||||
vault-data:
|
||||
meilisearch-data:
|
||||
libretranslate-data:
|
||||
34
docker/caddy/Caddyfile
Normal file
34
docker/caddy/Caddyfile
Normal file
@@ -0,0 +1,34 @@
|
||||
:80 {
|
||||
root * /app/public
|
||||
|
||||
handle_path /stats/* {
|
||||
rewrite * {uri}
|
||||
reverse_proxy https://tools-security.esy-web.dev {
|
||||
header_up Host tools-security.esy-web.dev
|
||||
}
|
||||
}
|
||||
|
||||
handle /assets/perf.js {
|
||||
rewrite * /beacon.min.js
|
||||
reverse_proxy https://static.cloudflareinsights.com {
|
||||
header_up Host static.cloudflareinsights.com
|
||||
}
|
||||
}
|
||||
|
||||
handle_path /sperf {
|
||||
rewrite * /cdn-cgi/rum
|
||||
reverse_proxy https://cloudflareinsights.com {
|
||||
header_up Host cloudflareinsights.com
|
||||
}
|
||||
}
|
||||
|
||||
php_fastcgi php:9000 {
|
||||
trusted_proxies private_ranges
|
||||
}
|
||||
|
||||
file_server
|
||||
|
||||
encode gzip
|
||||
|
||||
try_files {path} /index.php?{query}
|
||||
}
|
||||
25
docker/cron/Dockerfile
Normal file
25
docker/cron/Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
||||
FROM php:8.4-fpm
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libpq-dev \
|
||||
libzip-dev \
|
||||
libicu-dev \
|
||||
cron \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& docker-php-ext-install pdo_pgsql intl \
|
||||
&& pecl install redis \
|
||||
&& docker-php-ext-enable redis \
|
||||
&& groupadd -g 1000 appuser && useradd -u 1000 -g appuser -m appuser
|
||||
|
||||
COPY crontab /etc/cron.d/app-crontab
|
||||
RUN chmod 0644 /etc/cron.d/app-crontab && crontab -u appuser /etc/cron.d/app-crontab
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# cron daemon requires root to manage user crontabs, jobs run as appuser
|
||||
USER root
|
||||
|
||||
CMD ["/entrypoint.sh"]
|
||||
7
docker/cron/crontab
Normal file
7
docker/cron/crontab
Normal file
@@ -0,0 +1,7 @@
|
||||
*/5 * * * * echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] START app:orders:expire-pending" >> /proc/1/fd/1 && php /app/bin/console app:orders:expire-pending --env=dev >> /proc/1/fd/1 2>&1 && echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] END app:orders:expire-pending" >> /proc/1/fd/1
|
||||
0 * * * * echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] START app:monitor:messenger" >> /proc/1/fd/1 && php /app/bin/console app:monitor:messenger --env=dev >> /proc/1/fd/1 2>&1 && echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] END app:monitor:messenger" >> /proc/1/fd/1
|
||||
0 3 * * * echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] START app:meilisearch:check-consistency" >> /proc/1/fd/1 && php /app/bin/console app:meilisearch:check-consistency --fix --env=dev >> /proc/1/fd/1 2>&1 && echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] END app:meilisearch:check-consistency" >> /proc/1/fd/1
|
||||
0 */6 * * * echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] START app:stripe:sync" >> /proc/1/fd/1 && php /app/bin/console app:stripe:sync --env=dev >> /proc/1/fd/1 2>&1 && echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] END app:stripe:sync" >> /proc/1/fd/1
|
||||
*/5 * * * * php /app/bin/console app:infra:snapshot --env=dev >> /proc/1/fd/1 2>&1
|
||||
0 4 * * * echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] START app:attestations:clean" >> /proc/1/fd/1 && php /app/bin/console app:attestations:clean --env=dev >> /proc/1/fd/1 2>&1 && echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] END app:attestations:clean" >> /proc/1/fd/1
|
||||
*/15 * * * * echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] START app:services:check" >> /proc/1/fd/1 && php /app/bin/console app:services:check --env=dev >> /proc/1/fd/1 2>&1 && echo "[$(date '+\%Y-\%m-\%d \%H:\%M:\%S')] END app:services:check" >> /proc/1/fd/1
|
||||
10
docker/cron/entrypoint.sh
Normal file
10
docker/cron/entrypoint.sh
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
echo "=== CRM Ecosplay Cron ==="
|
||||
echo "Registered tasks:"
|
||||
echo " - */5 * * * * app:orders:expire-pending"
|
||||
echo " - 0 * * * * app:monitor:messenger"
|
||||
echo " - 0 3 * * * app:meilisearch:check-consistency --fix"
|
||||
echo " - 0 4 * * * app:attestations:clean"
|
||||
echo " - */15 * * * app:services:check"
|
||||
echo "===================="
|
||||
exec cron -f
|
||||
29
docker/ngrok/sync.sh
Executable file
29
docker/ngrok/sync.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "Waiting for ngrok to start..."
|
||||
sleep 5
|
||||
|
||||
NGROK_URL=""
|
||||
RETRIES=10
|
||||
|
||||
while [ -z "$NGROK_URL" ] && [ "$RETRIES" -gt 0 ]; do
|
||||
NGROK_URL=$(curl -s http://ngrok:4040/api/tunnels | grep -o '"public_url":"https://[^"]*"' | head -1 | cut -d'"' -f4)
|
||||
if [ -z "$NGROK_URL" ]; then
|
||||
echo "Waiting for tunnel..."
|
||||
sleep 2
|
||||
RETRIES=$((RETRIES - 1))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$NGROK_URL" ]; then
|
||||
echo "ERROR: Could not get ngrok URL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
touch /app/.env.local
|
||||
sed -i '/^OUTSIDE_URL=/d' /app/.env.local
|
||||
echo "OUTSIDE_URL=$NGROK_URL" >> /app/.env.local
|
||||
|
||||
echo "Ngrok URL: $NGROK_URL"
|
||||
echo "Written to .env.local"
|
||||
12
docker/pgsql/init-master.sh
Executable file
12
docker/pgsql/init-master.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||
CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'crm-ecosplay';
|
||||
SELECT pg_create_physical_replication_slot('slave_slot');
|
||||
EOSQL
|
||||
|
||||
echo "host replication replicator 0.0.0.0/0 md5" >> "$PGDATA/pg_hba.conf"
|
||||
echo "host all all 0.0.0.0/0 md5" >> "$PGDATA/pg_hba.conf"
|
||||
|
||||
pg_ctl reload -D "$PGDATA"
|
||||
2
docker/pgsql/init-master.sql
Normal file
2
docker/pgsql/init-master.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'crm-ecosplay';
|
||||
SELECT pg_create_physical_replication_slot('slave_slot');
|
||||
20
docker/pgsql/init-slave.sh
Executable file
20
docker/pgsql/init-slave.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
until pg_isready -h db-master -U crm-ecosplay; do
|
||||
echo "Waiting for master..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "db-master:5432:replication:replicator:crm-ecosplay" > /tmp/.pgpass
|
||||
chown postgres:postgres /tmp/.pgpass
|
||||
chmod 600 /tmp/.pgpass
|
||||
|
||||
rm -rf "$PGDATA"/*
|
||||
chown postgres:postgres "$PGDATA"
|
||||
chmod 700 "$PGDATA"
|
||||
su-exec postgres env PGPASSFILE=/tmp/.pgpass pg_basebackup -h db-master -D "$PGDATA" -U replicator -Fp -Xs -P -R
|
||||
|
||||
echo "hot_standby = on" >> "$PGDATA/postgresql.conf"
|
||||
|
||||
exec su-exec postgres "$@"
|
||||
22
docker/pgsql/pgbouncer-dev.ini
Normal file
22
docker/pgsql/pgbouncer-dev.ini
Normal file
@@ -0,0 +1,22 @@
|
||||
[databases]
|
||||
crm_ecosplay = host=database port=5432 dbname=crm_ecosplay
|
||||
crm_ecosplay_test = host=database port=5432 dbname=crm_ecosplay_test
|
||||
|
||||
[pgbouncer]
|
||||
listen_addr = 0.0.0.0
|
||||
listen_port = 6432
|
||||
auth_type = plain
|
||||
auth_file = /etc/pgbouncer/userlist.txt
|
||||
pool_mode = transaction
|
||||
max_client_conn = 200
|
||||
default_pool_size = 20
|
||||
min_pool_size = 5
|
||||
reserve_pool_size = 5
|
||||
reserve_pool_timeout = 3
|
||||
server_lifetime = 3600
|
||||
server_idle_timeout = 600
|
||||
log_connections = 0
|
||||
log_disconnections = 0
|
||||
ignore_startup_parameters = extra_float_digits
|
||||
admin_users = app
|
||||
stats_users = app
|
||||
1
docker/pgsql/userlist-dev.txt
Normal file
1
docker/pgsql/userlist-dev.txt
Normal file
@@ -0,0 +1 @@
|
||||
"app" "secret"
|
||||
35
docker/php/dev/Dockerfile
Normal file
35
docker/php/dev/Dockerfile
Normal file
@@ -0,0 +1,35 @@
|
||||
# hadolint global ignore=DL3008
|
||||
FROM php:8.4-fpm
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libpq-dev \
|
||||
libsqlite3-dev \
|
||||
libzip-dev \
|
||||
libxml2-dev \
|
||||
libicu-dev \
|
||||
libpng-dev \
|
||||
libjpeg-dev \
|
||||
libfreetype-dev \
|
||||
libmagickwand-dev \
|
||||
unzip \
|
||||
qpdf \
|
||||
curl \
|
||||
python3 \
|
||||
python3-pip \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||
&& docker-php-ext-install \
|
||||
pdo_mysql \
|
||||
pdo_pgsql \
|
||||
pdo_sqlite \
|
||||
zip \
|
||||
intl \
|
||||
gd \
|
||||
&& pecl install redis imagick pcov \
|
||||
&& docker-php-ext-enable redis imagick pcov \
|
||||
&& groupadd -g 1000 appuser && useradd -u 1000 -g appuser -m appuser
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
USER appuser
|
||||
35
docker/php/prod/Dockerfile
Normal file
35
docker/php/prod/Dockerfile
Normal file
@@ -0,0 +1,35 @@
|
||||
# hadolint global ignore=DL3008
|
||||
FROM php:8.4-fpm
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libpq-dev \
|
||||
libsqlite3-dev \
|
||||
libzip-dev \
|
||||
libxml2-dev \
|
||||
libicu-dev \
|
||||
libpng-dev \
|
||||
libjpeg-dev \
|
||||
libfreetype-dev \
|
||||
libmagickwand-dev \
|
||||
unzip \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||
&& docker-php-ext-install \
|
||||
pdo_mysql \
|
||||
pdo_pgsql \
|
||||
pdo_sqlite \
|
||||
zip \
|
||||
intl \
|
||||
gd \
|
||||
exif \
|
||||
opcache \
|
||||
&& pecl install redis imagick \
|
||||
&& docker-php-ext-enable redis imagick \
|
||||
&& groupadd -g 1000 appuser && useradd -u 1000 -g appuser -m appuser
|
||||
|
||||
COPY php.ini /usr/local/etc/php/conf.d/app.ini
|
||||
COPY opcache.ini /usr/local/etc/php/conf.d/opcache.ini
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
USER appuser
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user