-
Notifications
You must be signed in to change notification settings - Fork 30
Dev #386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Dev #386
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| # This file is a "template" of what your .env file should look like. | ||
| # Set variables here that may be different on each deployment target of the app, | ||
| # e.g. development, staging, production. | ||
| # | ||
| # On `composer install`/`composer update`, this file is copied to `.env` (unless | ||
| # it already exists) and PHPLIST_SECRET is replaced with a freshly generated value. | ||
| # | ||
| # https://symfony.com/doc/current/configuration.html#configuring-environment-variables-in-env-files | ||
|
|
||
| PHPLIST_DATABASE_DRIVER=pdo_mysql | ||
| PHPLIST_DATABASE_PATH= | ||
| PHPLIST_DATABASE_HOST=127.0.0.1 | ||
| PHPLIST_DATABASE_PORT=3306 | ||
| PHPLIST_DATABASE_NAME=phplistdb | ||
| PHPLIST_DATABASE_USER=phplist | ||
| PHPLIST_DATABASE_PASSWORD=phplist | ||
| DATABASE_PREFIX=phplist_ | ||
| LIST_TABLE_PREFIX=listattr_ | ||
| PHPLIST_ADMIN_PASSWORD=admin | ||
|
|
||
| APP_DEV_VERSION=0 | ||
| APP_DEV_EMAIL=dev@dev.com | ||
| APP_POWERED_BY_PHPLIST=0 | ||
| PREFERENCEPAGE_SHOW_PRIVATE_LISTS=0 | ||
|
|
||
| API_BASE_URL=http://api.phplist.local/ | ||
| FRONT_END_BASE_URL=http://frontend.phplist.local | ||
|
|
||
| PARALLER_USE_WITH_PHPLIST3=0 | ||
|
|
||
| # Email configuration | ||
| MAILER_FROM=noreply@phplist.com | ||
| MAILER_DSN=null://null | ||
| CONFIRMATION_URL=http://api.phplist.local/api/v2/subscriber/confirm/ | ||
| SUBSCRIPTION_CONFIRMATION_URL=http://api.phplist.local/api/v2/subscription/confirm/ | ||
| PASSWORD_RESET_URL=https://example.com/reset/ | ||
| SHOW_UNSUBSCRIBELINK=1 | ||
|
|
||
| # Bounce email settings | ||
| BOUNCE_EMAIL=bounce@phplist.com | ||
| BOUNCE_IMAP_PASS=bounce@phplist.com | ||
| BOUNCE_IMAP_HOST=imap.phplist.com | ||
| BOUNCE_IMAP_PORT=993 | ||
| BOUNCE_IMAP_ENCRYPTION=ssl | ||
| BOUNCE_IMAP_MAILBOX=/var/spool/mail/bounces | ||
| BOUNCE_IMAP_MAILBOX_NAME=INBOX,ONE_MORE | ||
| BOUNCE_IMAP_PROTOCOL=imap | ||
| BOUNCE_IMAP_UNSUBSCRIBE_THRESHOLD=5 | ||
| BOUNCE_IMAP_BLACKLIST_THRESHOLD=3 | ||
| BOUNCE_IMAP_PURGE=0 | ||
| BOUNCE_IMAP_PURGE_UNPROCESSED=0 | ||
|
|
||
| # Messenger configuration for asynchronous processing | ||
| MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=true | ||
|
|
||
| # A secret key that's used to generate certain security-related tokens | ||
| PHPLIST_SECRET=%s | ||
| VERIFY_SSL=1 | ||
|
Comment on lines
+56
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^|/)(\.env\.dist|Bootstrap\.php|composer\.json)$|Dotenv' || true
echo
echo "== .env.dist relevant lines =="
if [ -f .env.dist ]; then
nl -ba .env.dist | sed -n '45,65p'
fi
echo
echo "== composer scripts and dotenv package version =="
if [ -f composer.json ]; then
sed -n '1,220p' composer.json | rg -n '"scripts"|"symfony/dotenv"|"require-dev":|"dotenv"' -C 4 || true
fi
echo
echo "== search for env.dist or Dotenv usage =="
rg -n 'env\.dist|Dotenv|loadEnv|PHPLIST_SECRET' -S . --glob '!vendor/**' --glob '!node_modules/**' || trueRepository: phpList/core Length of output: 282 🌐 Web query:
💡 Result: In Symfony 6.4, the loadEnv method in the Dotenv component implements a specific fallback mechanism for the.env file. According to the source code (Dotenv.php), if the primary.env file is missing, the component will automatically attempt to load the.env.dist file if it exists [1][2][3]. The specific logic within loadEnv is implemented as follows: if (is_file($path) ||!is_file($p = "$path.dist")) { $this->doLoad($overrideExistingVars, [$path]); } else { $this->doLoad($overrideExistingVars, [$p]); } This means that if the provided path (usually.env) is not found (is_file($path) is false) AND a file with a.dist extension exists at that location (.env.dist), the Dotenv component will load the.env.dist file instead [1][2][4]. Key points regarding this behavior: - Fallback Priority: The primary.env file always takes precedence. The.env.dist file is only used as a fallback when the primary.env file is absent [1][3]. - Modern Usage: While this fallback exists for compatibility, modern Symfony best practices emphasize that.env should be committed to the repository containing non-sensitive default values, effectively replacing the historical role of.env.dist [5]. - Overriding: This loading process respects the overrideExistingVars parameter, which determines whether values from these files can override environment variables already set by the system [6][1]. System environment variables generally always have the highest precedence and cannot be overridden by Dotenv files unless explicitly configured [5][7]. Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== .env.dist relevant lines =="
if [ -f .env.dist ]; then
awk '{printf "%6d %s\n", NR, $0}' .env.dist | sed -n '45,65p'
fi
echo
echo "== composer relevant snippets =="
if [ -f composer.json ]; then
python3 - <<'PY'
import json, re, sys
from pathlib import Path
p=Path('composer.json')
text=p.read_text()
try: data=json.loads(text)
except Exception as e:
print("json_parse_error", repr(e))
for line in text.splitlines()[:240]:
if any(s in line for s in ['scripts', 'symfony/dotenv', '"dotenv"', 'require-dev', 'require']):
print(line)
sys.exit(0)
print("scripts:", data.get("scripts"))
print("symfony/dotenv:", data.get("require", {}).get("symfony/dotenv"), data.get("require-dev", {}).get("symfony/dotenv"))
for key in ("require","require-dev"):
for pk,ve in data.get(key,{}).items():
if "dot" in pk.lower() or "symfony" in pk.lower():
print(key, pk, ve)
PY
fi
echo
echo "== Bootstrap.php outlines/snippets =="
if [ -f src/Core/Bootstrap.php ]; then
wc -l src/Core/Bootstrap.php
rg -n 'Dotenv|loadEnv|env\.dist|load\\(|PHPLIST_SECRET|try|catch' src/Core/Bootstrap.php -C 8
fi
echo
echo "== repository-wide env.dist/env.load/fallback =="
rg -n 'env\.dist|loadEnv\\(|new Dotenv|Dotenv::|PHPLIST_SECRET|secret' -S src composer.json .env.dist --glob '!vendor/**' --glob '!node_modules/**' || trueRepository: phpList/core Length of output: 2686 🌐 Web query:
💡 Result: In Symfony, the Dotenv component's loadEnv method is designed to handle environment file loading automatically, including a fallback mechanism for the.env.dist file [1][2][3]. When calling $dotenv->loadEnv($projectRoot. '/.env'), the component follows these behaviors: 1. Fallback to.env.dist: If a.env file does not exist, the component will load.env.dist if it is present [1][3]. This was implemented to allow projects to define environment variables in.env.dist when a local.env file is intentionally omitted [1]. 2. Loading Order: The loadEnv method loads files in a specific order, where subsequent files can override variables defined in previously loaded files [2][4][3]. The standard sequence (subject to file existence) is: -.env (or.env.dist if.env is missing) [2][3] -.env.local (skipped for the "test" environment) [2][4][3] -.env.$env (based on the APP_ENV variable) [2][3] -.env.$env.local [2][3] This logic is typically invoked in the project's bootstrap file (e.g., config/bootstrap.php) to ensure environment variables are populated before the application kernel or other components are initialized [5][3]. Note that actual system environment variables always take precedence over values defined in these.env files [6]. Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== .env.dist relevant lines =="
if [ -f .env.dist ]; then
awk '{printf "%6d %s\n", NR, $0}' .env.dist | sed -n '45,65p'
fi
echo
echo "== composer relevant snippets =="
if [ - f composer.json ]; then
python3 - <<'PY'
import json, re, sys
from pathlib import Path
p=Path('composer.json')
text=p.read_text()
try: data=json.loads(text)
except Exception as e:
print("json_parse_error", repr(e))
for line in text.splitlines()[:240]:
if any(s in line for s in ['scripts', 'symfony/dotenv', '"dotenv"', 'require-dev', 'require']):
print(line)
sys.exit(0)
print("scripts:", data.get("scripts"))
print("symfony/dotenv:", data.get("require", {}).get("symfony/dotenv"), data.get("require-dev", {}).get("symfony/dotenv"))
for key in ("require","require-dev"):
for pk,ve in data.get(key,{}).items():
if "dot" in pk.lower() or "symfony" in pk.lower():
print(key, pk, ve)
PY
fi
echo
echo "== Bootstrap.php outlines/snippets =="
if [ -f src/Core/Bootstrap.php ]; then
wc -l src/Core/Bootstrap.php
rg -n 'Dotenv|loadEnv|env\.dist|load\\(|PHPLIST_SECRET|try|catch' src/Core/Bootstrap.php -C 8
fi
echo
echo "== repository-wide env.dist/env.load/fallback =="
rg -n 'env\.dist|loadEnv\\(|new Dotenv|Dotenv::|PHPLIST_SECRET|secret' -S src composer.json .env.dist --glob '!vendor/**' --glob '!node_modules/**' || trueRepository: phpList/core Length of output: 1181 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== Bootstrap.php Bootstrap.php matches =="
rg -n 'Dotenv|loadEnv|PHPLIST_SECRET|throw new|secret' src/Core/Bootstrap.php composer.json --glob '!vendor/**' --glob '!node_modules/**' || true
echo
echo "== src/Core/Bootstrap.php line 1-180 =="
awk '{printf "%6d %s\n", NR, $0}' src/Core/Bootstrap.php | sed -n '1,180p'
echo
echo "== src/Core/Bootstrap.php exact Dotenv/loadEnv snippets =="
awk '{printf "%6d %s\n", NR, $0}' src/Core/Bootstrap.php | sed -n '/Dotenv/,+8p;/loadEnv/,+12p;/PHPLIST_SECRET/,+12p'Repository: phpList/core Length of output: 10010 🌐 Web query:
💡 Result: In Symfony's Dotenv component (including version 6.4), the logic regarding Citations:
Don’t let
🤖 Prompt for AI AgentsSource: MCP tools |
||
|
|
||
| APP_PHPLIST_ISP_CONF_PATH=/etc/phplist.conf | ||
|
|
||
| # Message sending | ||
| MAILQUEUE_BATCH_SIZE=5 | ||
| MAILQUEUE_BATCH_PERIOD=5 | ||
| MAILQUEUE_THROTTLE=5 | ||
| MESSAGING_MAX_PROCESS_TIME=600 | ||
| MAX_MAILSIZE=209715200 | ||
| DEFAULT_MESSAGEAGE=691200 | ||
| USE_MANUAL_TEXT_PART=0 | ||
| MESSAGING_BLACKLIST_GRACE_TIME=600 | ||
| GOOGLE_SENDERID= | ||
| USE_AMAZONSES=0 | ||
| USE_PRECEDENCE_HEADER=0 | ||
| EMBEDEXTERNALIMAGES=0 | ||
| EMBEDUPLOADIMAGES=0 | ||
| EXTERNALIMAGE_MAXAGE=0 | ||
| EXTERNALIMAGE_TIMEOUT=30 | ||
| EXTERNALIMAGE_MAXSIZE=204800 | ||
| FORWARD_ALTERNATIVE_CONTENT=0 | ||
| EMAILTEXTCREDITS=0 | ||
| ALWAYS_ADD_USERTRACK=1 | ||
| SEND_LISTADMIN_COPY=0 | ||
|
|
||
| FORWARD_EMAIL_PERIOD="1 minute" | ||
| FORWARD_EMAIL_COUNT=1 | ||
| FORWARD_PERSONAL_NOTE_SIZE=0 | ||
| FORWARD_FRIEND_COUNT_ATTRIBUTE= | ||
| KEEPFORWARDERATTRIBUTES=0 | ||
|
|
||
| UPLOADIMAGES_DIR=uploadimages | ||
| PHPLIST_UPLOADS_MAX_SIZE=5M | ||
|
|
||
| PUBLIC_SCHEMA=https | ||
| PHPLIST_ATTACHMENT_DOWNLOAD_URL=https://example.com/download/ | ||
| PHPLIST_ATTACHMENT_REPOSITORY_PATH=/tmp | ||
| MAX_AVATAR_SIZE=100000 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,8 +7,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). | |
|
|
||
| ### Added | ||
| - Graylog integration for centralized logging (#TBD) | ||
| - `symfony/dotenv` support: configuration values are now read from a `.env` file (generated from `.env.dist` on install/update), in addition to real environment variables (#TBD) | ||
|
|
||
| ### Changed | ||
| - `config/parameters.yml.dist` no longer contains inline `env(VAR): default` fallbacks; defaults now live in `.env.dist` (#TBD) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Use the current parameters template path. This entry names 🤖 Prompt for AI Agents |
||
|
|
||
| ### Deprecated | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| # This file is a "template" of what your parameters.yml file should look like | ||
| # Set parameters here that may be different on each deployment target of the app, e.g. development, staging, production. | ||
| # https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration | ||
| # | ||
| # These variables are read from environment variables using the "env" construct. | ||
| # The environment variables themselves are defined in the ".env" file (see ".env.dist" for the template) | ||
| # and/or in the actual environment (e.g. Apache host configuration, command line). | ||
| parameters: | ||
| database_driver: '%env(PHPLIST_DATABASE_DRIVER)%' | ||
| database_path: '%env(PHPLIST_DATABASE_PATH)%' | ||
| database_host: '%env(PHPLIST_DATABASE_HOST)%' | ||
| database_port: '%env(PHPLIST_DATABASE_PORT)%' | ||
| database_name: '%env(PHPLIST_DATABASE_NAME)%' | ||
| database_user: '%env(PHPLIST_DATABASE_USER)%' | ||
| database_password: '%env(PHPLIST_DATABASE_PASSWORD)%' | ||
| database_prefix: '%env(DATABASE_PREFIX)%' | ||
| app.default_admin_password: '%env(PHPLIST_DEFAULT_ADMIN_PASSWORD)%' | ||
| list_table_prefix: '%env(LIST_TABLE_PREFIX)%' | ||
| app.dev_version: '%env(APP_DEV_VERSION)%' | ||
| app.dev_email: '%env(APP_DEV_EMAIL)%' | ||
| app.powered_by_phplist: '%env(APP_POWERED_BY_PHPLIST)%' | ||
| app.preference_page_show_private_lists: '%env(PREFERENCEPAGE_SHOW_PRIVATE_LISTS)%' | ||
|
|
||
| app.rest_api_base_url: '%env(API_BASE_URL)%/api/v2' | ||
| app.api_base_url: '%env(API_BASE_URL)%' | ||
| app.frontend_base_url: '%env(FRONT_END_BASE_URL)%' | ||
|
|
||
| parallel_use_with_phplist3: '%env(PARALLER_USE_WITH_PHPLIST3)%' | ||
|
|
||
| # Email configuration | ||
| app.mailer_from: '%env(MAILER_FROM)%' | ||
| app.mailer_dsn: '%env(MAILER_DSN)%' | ||
| app.confirmation_url: '%env(CONFIRMATION_URL)%' | ||
| app.subscription_confirmation_url: '%env(SUBSCRIPTION_CONFIRMATION_URL)%' | ||
| app.password_reset_url: '%env(PASSWORD_RESET_URL)%' | ||
| app.show_unsubscribe_link: '%env(SHOW_UNSUBSCRIBELINK)%' | ||
|
|
||
| # bounce email settings | ||
| imap_bounce.email: '%env(BOUNCE_EMAIL)%' | ||
| imap_bounce.password: '%env(BOUNCE_IMAP_PASS)%' | ||
| imap_bounce.host: '%env(BOUNCE_IMAP_HOST)%' | ||
| imap_bounce.port: '%env(BOUNCE_IMAP_PORT)%' | ||
| imap_bounce.encryption: '%env(BOUNCE_IMAP_ENCRYPTION)%' | ||
| imap_bounce.mailbox: '%env(BOUNCE_IMAP_MAILBOX)%' | ||
| imap_bounce.mailbox_name: '%env(BOUNCE_IMAP_MAILBOX_NAME)%' | ||
| imap_bounce.protocol: '%env(BOUNCE_IMAP_PROTOCOL)%' | ||
| imap_bounce.unsubscribe_threshold: '%env(BOUNCE_IMAP_UNSUBSCRIBE_THRESHOLD)%' | ||
| imap_bounce.blacklist_threshold: '%env(BOUNCE_IMAP_BLACKLIST_THRESHOLD)%' | ||
| imap_bounce.purge: '%env(BOUNCE_IMAP_PURGE)%' | ||
| imap_bounce.purge_unprocessed: '%env(BOUNCE_IMAP_PURGE_UNPROCESSED)%' | ||
|
|
||
| # Messenger configuration for asynchronous processing | ||
| app.messenger_transport_dsn: '%env(MESSENGER_TRANSPORT_DSN)%' | ||
|
|
||
| # A secret key that's used to generate certain security-related tokens | ||
| secret: '%env(PHPLIST_SECRET)%' | ||
| phplist.verify_ssl: '%env(VERIFY_SSL)%' | ||
|
|
||
| graylog_host: 'graylog.phplist.local' | ||
| graylog_port: 12201 | ||
|
|
||
| app.phplist_isp_conf_path: '%env(APP_PHPLIST_ISP_CONF_PATH)%' | ||
|
|
||
| # Message sending | ||
| messaging.mail_queue_batch_size: '%env(MAILQUEUE_BATCH_SIZE)%' | ||
| messaging.mail_queue_period: '%env(MAILQUEUE_BATCH_PERIOD)%' | ||
| messaging.mail_queue_throttle: '%env(MAILQUEUE_THROTTLE)%' | ||
| messaging.max_process_time: '%env(MESSAGING_MAX_PROCESS_TIME)%' | ||
| messaging.max_mail_size: '%env(MAX_MAILSIZE)%' | ||
| messaging.default_message_age: '%env(DEFAULT_MESSAGEAGE)%' | ||
| messaging.use_manual_text_part: '%env(USE_MANUAL_TEXT_PART)%' | ||
| messaging.blacklist_grace_time: '%env(MESSAGING_BLACKLIST_GRACE_TIME)%' | ||
| messaging.google_sender_id: '%env(GOOGLE_SENDERID)%' | ||
| messaging.use_amazon_ses: '%env(USE_AMAZONSES)%' | ||
| messaging.use_precedence_header: '%env(USE_PRECEDENCE_HEADER)%' | ||
| messaging.embed_external_images: '%env(EMBEDEXTERNALIMAGES)%' | ||
| messaging.embed_uploaded_images: '%env(EMBEDUPLOADIMAGES)%' | ||
| messaging.external_image_max_age: '%env(EXTERNALIMAGE_MAXAGE)%' | ||
| messaging.external_image_timeout: '%env(EXTERNALIMAGE_TIMEOUT)%' | ||
| messaging.external_image_max_size: '%env(EXTERNALIMAGE_MAXSIZE)%' | ||
| messaging.forward_alternative_content: '%env(FORWARD_ALTERNATIVE_CONTENT)%' | ||
| messaging.email_text_credits: '%env(EMAILTEXTCREDITS)%' | ||
| messaging.always_add_user_track: '%env(ALWAYS_ADD_USERTRACK)%' | ||
| messaging.send_list_admin_copy: '%env(SEND_LISTADMIN_COPY)%' | ||
|
|
||
| phplist.forward_email_period: '%env(FORWARD_EMAIL_PERIOD)%' | ||
| phplist.forward_email_count: '%env(FORWARD_EMAIL_COUNT)%' | ||
| phplist.forward_personal_note_size: '%env(FORWARD_PERSONAL_NOTE_SIZE)%' | ||
| phplist.forward_friend_count_attribute: '%env(FORWARD_FRIEND_COUNT_ATTRIBUTE)%' | ||
| phplist.keep_forwarded_attributes: '%env(KEEPFORWARDERATTRIBUTES)%' | ||
|
|
||
| phplist.upload_images_dir: '%env(UPLOADIMAGES_DIR)%' | ||
| phplist.uploads.allowed_mime_types: ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml'] | ||
| phplist.uploads.allowed_extensions: ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'] | ||
| phplist.uploads.max_size: '%env(PHPLIST_UPLOADS_MAX_SIZE)%' | ||
|
|
||
| phplist.public_schema: '%env(PUBLIC_SCHEMA)%' | ||
| phplist.attachment_download_url: '%env(PHPLIST_ATTACHMENT_DOWNLOAD_URL)%' | ||
| phplist.attachment_repository_path: '%env(PHPLIST_ATTACHMENT_REPOSITORY_PATH)%' | ||
| phplist.max_avatar_size: '%env(MAX_AVATAR_SIZE)%' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Do not ship a usable default administrator password.
When
.envis absent,src/Core/Bootstrap.php:162-170loads.env.dist. This can makeadminthe administrator password. Replace this value with a non-operational placeholder and fail fast until deployment provides a strong password. Alternatively, stop loading.env.distas a runtime fallback.Proposed template change
🧰 Tools
🪛 dotenv-linter (4.0.0)
[warning] 19-19: [UnorderedKey] The PHPLIST_ADMIN_PASSWORD key should go before the PHPLIST_DATABASE_DRIVER key
(UnorderedKey)
🤖 Prompt for AI Agents