mirror of
https://github.com/okxlin/appstore.git
synced 2026-09-23 08:01:00 +00:00
237 lines
11 KiB
Bash
Executable File
237 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ENV_FILE="${ENV_FILE:-./.env}"
|
|
MASTODON_IMAGE="lscr.io/linuxserver/mastodon:latest"
|
|
LEGACY_DB_PASSWORD="mastodon-change-me"
|
|
LEGACY_ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY="fGWkJDBwyRYhILyO7akZGLSSz0gAjPpo"
|
|
LEGACY_ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY="Z8BE3tc3XnmUr0MbRexRiPN7vcP52VX0"
|
|
LEGACY_ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT="3hRwOaLRCikUCsxd19cUcO5EgXCN6ig1"
|
|
LEGACY_SECRET_KEY_BASE="ae3ab77b9a041a4d760126dba8c4e24a33bdfcec7fdbadf3d973baf92017ee0d0b988d62c040aca882ee8030ea22adb04d9c26a9541c918a434029840c8719b0"
|
|
LEGACY_OTP_SECRET="b3d6069b87df718c733a1b17a9adcbd7705b76ba0b48dd3f3ce58870dd52bed0d32d947a43a4eadac4230d508e11df0cee6f59ed85e40670134a52545f1131ac"
|
|
LEGACY_VAPID_PRIVATE_KEY="1eF670mQsgs_-W_eb06ZZ46apD4qVDYNvFWu9eGWc7E="
|
|
LEGACY_VAPID_PUBLIC_KEY="BOOqXKvCVA9tb8Bas05sdez6fGavnA5SrDJe88s7FMeIu7txiQ5sOqOZqKIpTSS_xmm5Wkd_MKHqj2UCQIwl9_8="
|
|
|
|
read_env_value() {
|
|
local key="$1"
|
|
|
|
if [[ ! -f "$ENV_FILE" ]] || ! grep -qE "^${key}=" "$ENV_FILE"; then
|
|
return
|
|
fi
|
|
|
|
local current
|
|
current="$(sed -n -E "s/^${key}=//p" "$ENV_FILE" | tail -n 1)"
|
|
current="${current%\"}"
|
|
current="${current#\"}"
|
|
current="${current%\'}"
|
|
current="${current#\'}"
|
|
printf '%s\n' "$current"
|
|
}
|
|
|
|
read_cache_value() {
|
|
local cache_file="$1"
|
|
if [[ ! -s "$cache_file" ]]; then
|
|
return
|
|
fi
|
|
sed -n '1p' "$cache_file" | tr -d '\r\n'
|
|
}
|
|
|
|
write_cache_value() {
|
|
local cache_file="$1"
|
|
local value="$2"
|
|
|
|
mkdir -p "$(dirname "$cache_file")"
|
|
printf '%s\n' "$value" > "$cache_file"
|
|
chmod 600 "$cache_file" 2>/dev/null || true
|
|
}
|
|
|
|
escape_sed_replacement() {
|
|
printf '%s' "$1" | sed -e 's/[\/&|]/\\&/g'
|
|
}
|
|
|
|
set_env_value() {
|
|
local key="$1"
|
|
local value="$2"
|
|
|
|
if [[ ! -f "$ENV_FILE" ]]; then
|
|
echo "$ENV_FILE not found; skipped $key generation"
|
|
return
|
|
fi
|
|
|
|
local replacement
|
|
replacement="$(escape_sed_replacement "$value")"
|
|
if grep -qE "^${key}=" "$ENV_FILE"; then
|
|
sed -i -E "s|^${key}=.*|${key}=${replacement}|" "$ENV_FILE"
|
|
echo "Updated $key"
|
|
return
|
|
fi
|
|
|
|
printf '%s=%s\n' "$key" "$value" >> "$ENV_FILE"
|
|
echo "Added $key"
|
|
}
|
|
|
|
generate_alnum_secret() {
|
|
local secret=""
|
|
local chunk=""
|
|
while [[ ${#secret} -lt 32 ]]; do
|
|
chunk="$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c $((32 - ${#secret})) || true)"
|
|
secret="${secret}${chunk}"
|
|
done
|
|
printf '%s\n' "$secret"
|
|
}
|
|
|
|
run_mastodon_generator() {
|
|
docker run --rm --entrypoint /bin/bash "$MASTODON_IMAGE" "$1"
|
|
}
|
|
|
|
extract_generator_value() {
|
|
local output="$1"
|
|
local key="$2"
|
|
printf '%s\n' "$output" | sed -n -E "s/^${key}=//p" | tail -n 1
|
|
}
|
|
|
|
is_active_record_secret_valid() {
|
|
local value="$1"
|
|
[[ "$value" =~ ^[A-Za-z0-9]{32}$ ]]
|
|
}
|
|
|
|
is_hex_secret_valid() {
|
|
local value="$1"
|
|
[[ "$value" =~ ^[a-f0-9]{128}$ ]]
|
|
}
|
|
|
|
is_vapid_key_valid() {
|
|
local value="$1"
|
|
[[ ${#value} -ge 40 && "$value" =~ ^[A-Za-z0-9_-]+=*$ ]]
|
|
}
|
|
|
|
CONFIG_PATH_VALUE="${CONFIG_PATH:-$(read_env_value CONFIG_PATH || true)}"
|
|
CONFIG_PATH_VALUE="${CONFIG_PATH_VALUE:-./data/config}"
|
|
SECRET_CACHE_DIR="${SECRET_CACHE_DIR:-${CONFIG_PATH_VALUE}/.mastodon_secret_cache}"
|
|
DB_PASSWORD_CACHE="${DB_PASSWORD_CACHE:-${SECRET_CACHE_DIR}/db_password}"
|
|
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY_CACHE="${ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY_CACHE:-${SECRET_CACHE_DIR}/active_record_encryption_primary_key}"
|
|
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY_CACHE="${ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY_CACHE:-${SECRET_CACHE_DIR}/active_record_encryption_deterministic_key}"
|
|
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT_CACHE="${ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT_CACHE:-${SECRET_CACHE_DIR}/active_record_encryption_key_derivation_salt}"
|
|
SECRET_KEY_BASE_CACHE="${SECRET_KEY_BASE_CACHE:-${SECRET_CACHE_DIR}/secret_key_base}"
|
|
OTP_SECRET_CACHE="${OTP_SECRET_CACHE:-${SECRET_CACHE_DIR}/otp_secret}"
|
|
VAPID_PRIVATE_KEY_CACHE="${VAPID_PRIVATE_KEY_CACHE:-${SECRET_CACHE_DIR}/vapid_private_key}"
|
|
VAPID_PUBLIC_KEY_CACHE="${VAPID_PUBLIC_KEY_CACHE:-${SECRET_CACHE_DIR}/vapid_public_key}"
|
|
|
|
if [[ -f "$ENV_FILE" ]]; then
|
|
db_password="$(read_env_value DB_PASSWORD || true)"
|
|
cached_db_password="$(read_cache_value "$DB_PASSWORD_CACHE" || true)"
|
|
if [[ -n "$db_password" && "$db_password" != "$LEGACY_DB_PASSWORD" ]]; then
|
|
write_cache_value "$DB_PASSWORD_CACHE" "$db_password"
|
|
elif [[ -n "$cached_db_password" ]]; then
|
|
set_env_value "DB_PASSWORD" "$cached_db_password"
|
|
else
|
|
db_password="$(generate_alnum_secret)"
|
|
set_env_value "DB_PASSWORD" "$db_password"
|
|
write_cache_value "$DB_PASSWORD_CACHE" "$db_password"
|
|
fi
|
|
|
|
active_primary="$(read_env_value ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY || true)"
|
|
active_deterministic="$(read_env_value ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY || true)"
|
|
active_salt="$(read_env_value ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT || true)"
|
|
cached_active_primary="$(read_cache_value "$ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY_CACHE" || true)"
|
|
cached_active_deterministic="$(read_cache_value "$ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY_CACHE" || true)"
|
|
cached_active_salt="$(read_cache_value "$ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT_CACHE" || true)"
|
|
if is_active_record_secret_valid "$active_primary" \
|
|
&& is_active_record_secret_valid "$active_deterministic" \
|
|
&& is_active_record_secret_valid "$active_salt" \
|
|
&& [[ "$active_primary" != "$LEGACY_ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY" ]] \
|
|
&& [[ "$active_deterministic" != "$LEGACY_ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY" ]] \
|
|
&& [[ "$active_salt" != "$LEGACY_ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT" ]]; then
|
|
write_cache_value "$ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY_CACHE" "$active_primary"
|
|
write_cache_value "$ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY_CACHE" "$active_deterministic"
|
|
write_cache_value "$ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT_CACHE" "$active_salt"
|
|
elif is_active_record_secret_valid "$cached_active_primary" \
|
|
&& is_active_record_secret_valid "$cached_active_deterministic" \
|
|
&& is_active_record_secret_valid "$cached_active_salt"; then
|
|
set_env_value "ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY" "$cached_active_primary"
|
|
set_env_value "ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY" "$cached_active_deterministic"
|
|
set_env_value "ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT" "$cached_active_salt"
|
|
elif [[ "$active_primary" == "$LEGACY_ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY" ]] \
|
|
|| [[ "$active_deterministic" == "$LEGACY_ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY" ]] \
|
|
|| [[ "$active_salt" == "$LEGACY_ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT" ]] \
|
|
|| ! is_active_record_secret_valid "$active_primary" \
|
|
|| ! is_active_record_secret_valid "$active_deterministic" \
|
|
|| ! is_active_record_secret_valid "$active_salt"; then
|
|
active_record_output="$(run_mastodon_generator generate-active-record)"
|
|
active_primary="$(extract_generator_value "$active_record_output" "ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY")"
|
|
active_deterministic="$(extract_generator_value "$active_record_output" "ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY")"
|
|
active_salt="$(extract_generator_value "$active_record_output" "ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT")"
|
|
set_env_value "ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY" "$active_primary"
|
|
set_env_value "ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY" "$active_deterministic"
|
|
set_env_value "ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT" "$active_salt"
|
|
write_cache_value "$ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY_CACHE" "$active_primary"
|
|
write_cache_value "$ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY_CACHE" "$active_deterministic"
|
|
write_cache_value "$ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT_CACHE" "$active_salt"
|
|
fi
|
|
|
|
secret_key_base="$(read_env_value SECRET_KEY_BASE || true)"
|
|
if [[ "$secret_key_base" == "$LEGACY_SECRET_KEY_BASE" ]] || ! is_hex_secret_valid "$secret_key_base"; then
|
|
cached_secret_key_base="$(read_cache_value "$SECRET_KEY_BASE_CACHE" || true)"
|
|
if is_hex_secret_valid "$cached_secret_key_base"; then
|
|
set_env_value "SECRET_KEY_BASE" "$cached_secret_key_base"
|
|
else
|
|
secret_key_base="$(run_mastodon_generator generate-secret | tail -n 1 | tr -d '\r\n')"
|
|
set_env_value "SECRET_KEY_BASE" "$secret_key_base"
|
|
write_cache_value "$SECRET_KEY_BASE_CACHE" "$secret_key_base"
|
|
fi
|
|
else
|
|
write_cache_value "$SECRET_KEY_BASE_CACHE" "$secret_key_base"
|
|
fi
|
|
|
|
otp_secret="$(read_env_value OTP_SECRET || true)"
|
|
if [[ "$otp_secret" == "$LEGACY_OTP_SECRET" ]] || ! is_hex_secret_valid "$otp_secret"; then
|
|
cached_otp_secret="$(read_cache_value "$OTP_SECRET_CACHE" || true)"
|
|
if is_hex_secret_valid "$cached_otp_secret"; then
|
|
set_env_value "OTP_SECRET" "$cached_otp_secret"
|
|
else
|
|
otp_secret="$(run_mastodon_generator generate-secret | tail -n 1 | tr -d '\r\n')"
|
|
set_env_value "OTP_SECRET" "$otp_secret"
|
|
write_cache_value "$OTP_SECRET_CACHE" "$otp_secret"
|
|
fi
|
|
else
|
|
write_cache_value "$OTP_SECRET_CACHE" "$otp_secret"
|
|
fi
|
|
|
|
vapid_private_key="$(read_env_value VAPID_PRIVATE_KEY || true)"
|
|
vapid_public_key="$(read_env_value VAPID_PUBLIC_KEY || true)"
|
|
cached_vapid_private_key="$(read_cache_value "$VAPID_PRIVATE_KEY_CACHE" || true)"
|
|
cached_vapid_public_key="$(read_cache_value "$VAPID_PUBLIC_KEY_CACHE" || true)"
|
|
if is_vapid_key_valid "$vapid_private_key" \
|
|
&& is_vapid_key_valid "$vapid_public_key" \
|
|
&& [[ "$vapid_private_key" != "$LEGACY_VAPID_PRIVATE_KEY" ]] \
|
|
&& [[ "$vapid_public_key" != "$LEGACY_VAPID_PUBLIC_KEY" ]]; then
|
|
write_cache_value "$VAPID_PRIVATE_KEY_CACHE" "$vapid_private_key"
|
|
write_cache_value "$VAPID_PUBLIC_KEY_CACHE" "$vapid_public_key"
|
|
elif is_vapid_key_valid "$cached_vapid_private_key" && is_vapid_key_valid "$cached_vapid_public_key"; then
|
|
set_env_value "VAPID_PRIVATE_KEY" "$cached_vapid_private_key"
|
|
set_env_value "VAPID_PUBLIC_KEY" "$cached_vapid_public_key"
|
|
elif [[ "$vapid_private_key" == "$LEGACY_VAPID_PRIVATE_KEY" ]] \
|
|
|| [[ "$vapid_public_key" == "$LEGACY_VAPID_PUBLIC_KEY" ]] \
|
|
|| ! is_vapid_key_valid "$vapid_private_key" \
|
|
|| ! is_vapid_key_valid "$vapid_public_key"; then
|
|
vapid_output="$(run_mastodon_generator generate-vapid)"
|
|
set_env_value "VAPID_PRIVATE_KEY" "$(extract_generator_value "$vapid_output" "VAPID_PRIVATE_KEY")"
|
|
set_env_value "VAPID_PUBLIC_KEY" "$(extract_generator_value "$vapid_output" "VAPID_PUBLIC_KEY")"
|
|
write_cache_value "$VAPID_PRIVATE_KEY_CACHE" "$(extract_generator_value "$vapid_output" "VAPID_PRIVATE_KEY")"
|
|
write_cache_value "$VAPID_PUBLIC_KEY_CACHE" "$(extract_generator_value "$vapid_output" "VAPID_PUBLIC_KEY")"
|
|
fi
|
|
fi
|
|
|
|
paths=(
|
|
"${CONFIG_PATH:-./data/config}"
|
|
"${DB_DATA_PATH:-./data/db}"
|
|
"${REDIS_DATA_PATH:-./data/redis}"
|
|
)
|
|
|
|
mkdir -p "${paths[@]}"
|
|
for path in "${paths[@]}"; do
|
|
case "$path" in
|
|
./*|../*) chown -R 1000:1000 "$path" 2>/dev/null || true ;;
|
|
esac
|
|
done
|