ShareDownload::$authenticated was a public property without #[Locked], so a visitor with a share's link but not its password could set it from the browser and see the file list: names, folder paths, sizes and whether the share holds a text. The contents stayed protected; the flag is now locked, and a test tries to set it. Sessions hold the keys of the password shares a recipient unlocked, and were stored unencrypted in the sessions table wherever SESSION_ENCRYPT was not set, which includes every Docker install. They are now encrypted unless SESSION_ENCRYPT=false. Share keys never live in the session, so every share stays readable; people sign in again once. The container generated an APP_KEY when none was set, printed it to the logs and generated another on the next start, which left the shares without a password unreadable. It now refuses to start without one and says how to create it; docker-compose.example.yml requires it for both services. The command it names, and the README's, now pass --entrypoint php: the image's entrypoint ignores its arguments, so "docker run <image> php artisan key:generate --show" never ran it. Every proxy is trusted, so the password-reset mail built its link from a host a forged X-Forwarded-Host could choose. It is now built from APP_URL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
2.1 KiB
Bash
Executable File
51 lines
2.1 KiB
Bash
Executable File
#!/bin/sh
|
|
set -e
|
|
|
|
cd /app
|
|
|
|
# APP_KEY decrypts the shares, so it must stay the same across restarts: a key made up here would
|
|
# change on the next start and leave every existing share unreadable.
|
|
if [ -z "$APP_KEY" ]; then
|
|
echo "[entrypoint] APP_KEY is not set. Create one and set it for the app and the scheduler:" >&2
|
|
echo "[entrypoint] docker run --rm --entrypoint php <this image> artisan key:generate --show" >&2
|
|
echo "[entrypoint] If this install ran without one before, use the key from its old logs" >&2
|
|
echo "[entrypoint] (\"Generated APP_KEY: ...\") so its shares stay readable." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# A docker-compose.yml from before 2.1.1 mounts the SQLite volume over all of /app/database, so the
|
|
# migrations folder is the one the volume was created with: add this image's newer migrations to it.
|
|
for migration in docker/migrations/*.php; do
|
|
if [ ! -e "database/migrations/${migration##*/}" ]; then
|
|
echo "[entrypoint] Adding migration ${migration##*/} to the database volume..."
|
|
mkdir -p database/migrations
|
|
cp "$migration" database/migrations/
|
|
fi
|
|
done
|
|
|
|
echo "[entrypoint] Running database migrations..."
|
|
php artisan migrate --force
|
|
|
|
echo "[entrypoint] Creating storage link..."
|
|
php artisan storage:link --force
|
|
|
|
echo "[entrypoint] Caching configuration..."
|
|
php artisan config:cache
|
|
php artisan route:cache
|
|
php artisan view:cache
|
|
|
|
# Uploads are encrypted in the browser, which browsers only allow over HTTPS: either this container
|
|
# fetches a certificate for SERVER_NAME itself, or a reverse proxy in front terminates TLS.
|
|
if [ "${AUTO_HTTPS:-false}" = "true" ]; then
|
|
if [ -z "$SERVER_NAME" ]; then
|
|
echo "[entrypoint] AUTO_HTTPS=true needs SERVER_NAME, the domain to fetch a certificate for." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "[entrypoint] Starting Octane (FrankenPHP) with automatic HTTPS for $SERVER_NAME..."
|
|
exec php artisan octane:frankenphp --host="$SERVER_NAME" --port=443 --https --http-redirect
|
|
fi
|
|
|
|
echo "[entrypoint] Starting Octane (FrankenPHP) on HTTP..."
|
|
exec php artisan octane:frankenphp --host=0.0.0.0 --port=80
|