پیشنمایش خصوصی دو بار احراز هویت میخواست (Basic Auth لبه + ورود خود پنل) و هر origin (www/apex/.ir) هم پرسش جداگانهای داشت؛ نتیجه سردرگمی تیم. حالا روترهای /admin و /api میدلور preview-auth ندارند (noindex میماند) و پنل با همان ورود خودش کار میکند؛ صفحات عمومی همچنان خصوصیاند.
135 lines
6.3 KiB
Bash
135 lines
6.3 KiB
Bash
#!/usr/bin/env bash
|
|
# پیشنمایش خصوصی و انتشار عمومی سایت.
|
|
#
|
|
# bash scripts/preview-mode.sh status # وضعیت فعلی
|
|
# bash scripts/preview-mode.sh on # سایت آنلاین ولی خصوصی (گیت ورود + noindex)
|
|
# bash scripts/preview-mode.sh off # انتشار عمومی (حذف گیت + اجازه ایندکس)
|
|
#
|
|
# در حالت «on» کل سایت پشت Basic Auth است: تیم با نام کاربری/رمز مشترک وارد میشود،
|
|
# محتوا را در همان سایت آنلاین ویرایش میکند (ویرایش درجای ایمیل/تلفن و بقیه محتوا)،
|
|
# اما نه عموم به سایت دسترسی دارند و نه گوگل چیزی ایندکس میکند.
|
|
#
|
|
# پس از هر تغییر، استک را دوباره بالا بیاورید:
|
|
# bash scripts/stack.sh deploy-prod
|
|
#
|
|
# با «فعال شدن» اولین بار، نام کاربری/رمز ساخته و در .env ذخیره میشود
|
|
# (پیشفرض: preview / یک رمز تصادفی — در خروجی چاپ میشود).
|
|
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
ENV_FILE=.env
|
|
[ -f "$ENV_FILE" ] || { echo "فایل .env پیدا نشد — اول bash scripts/gen-env.sh" >&2; exit 1; }
|
|
|
|
# مقدار فعلی یک کلید در .env (یا خالی) — کوتیشن تکنویسهای هم برداشته میشود
|
|
env_get() {
|
|
local key="$1"
|
|
sed -n "s/^${key}=//p" "$ENV_FILE" | tail -1 | sed -e "s/^'//" -e "s/'\$//"
|
|
}
|
|
|
|
# تنظیم/جایگزینی یک کلید در .env (بدون آسیب به بقیه خطوط)
|
|
# نکتهٔ مهم: docker compose مقادیر .env را خودش تفسیر میکند؛ هش htpasswd شامل
|
|
# $apr1$... است و اگر کوتیشن نخورد، $apr1 و بخشهای بعدی بهعنوان متغیر خالی
|
|
# جایگزین میشوند و Basic Auth هرگز رمز را نمیپذیرد. پس هر مقدار دارای $ را
|
|
# تککوتیشن میگذاریم (compose کوتیشن را برمیدارد و مقدار را عیناً میخواند).
|
|
env_set() {
|
|
local key="$1" value="$2"
|
|
if grep -q "^${key}=" "$ENV_FILE"; then
|
|
python3 - "$ENV_FILE" "$key" "$value" <<'PY'
|
|
import io, sys
|
|
path, key, value = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
if "$" in value:
|
|
value = "'" + value + "'"
|
|
lines = io.open(path, encoding="utf-8").read().split("\n")
|
|
out = [f"{key}={value}" if line.startswith(f"{key}=") else line for line in lines]
|
|
io.open(path, "w", encoding="utf-8", newline="\n").write("\n".join(out))
|
|
PY
|
|
else
|
|
if [ "${value#*\$}" != "$value" ]; then value="'$value'"; fi
|
|
printf '\n%s=%s\n' "$key" "$value" >> "$ENV_FILE"
|
|
fi
|
|
}
|
|
|
|
# ساخت هش htpasswd — اول با openssl، در نبودش با ایمیج httpd (Docker لازم است)
|
|
make_htpasswd() {
|
|
local user="$1" pass="$2" hash
|
|
if command -v openssl >/dev/null 2>&1; then
|
|
hash=$(openssl passwd -apr1 "$pass")
|
|
else
|
|
hash=$(docker run --rm httpd:2.4-alpine htpasswd -nbB "$user" "$pass" | cut -d: -f2)
|
|
fi
|
|
printf '%s:%s' "$user" "$hash"
|
|
}
|
|
|
|
# رمز تصادفی خوانا (بدون نویسههای گیجکننده)
|
|
random_password() {
|
|
python3 - <<'PY'
|
|
import secrets, string
|
|
alphabet = string.ascii_letters + string.digits
|
|
print("".join(secrets.choice(alphabet) for _ in range(16)))
|
|
PY
|
|
}
|
|
|
|
PREVIEW_MIDDLEWARES_VALUE="preview-auth@docker,preview-noindex@docker"
|
|
|
|
case "${1:-status}" in
|
|
on)
|
|
users="$(env_get PREVIEW_AUTH_USERS)"
|
|
if [ -z "$users" ]; then
|
|
password="$(random_password)"
|
|
users="$(make_htpasswd preview "$password")"
|
|
env_set PREVIEW_AUTH_USERS "$users"
|
|
echo "نام کاربری/رمز پیشنمایش ساخته شد:"
|
|
echo " کاربر: preview"
|
|
echo " رمز: $password"
|
|
echo " (این رمز فقط همین یکبار چاپ میشود — در .env ذخیره شده است)"
|
|
echo ""
|
|
fi
|
|
env_set PREVIEW_MODE on
|
|
env_set PREVIEW_MIDDLEWARES "$PREVIEW_MIDDLEWARES_VALUE"
|
|
# /api و /admin گیت Basic Auth نمیگیرند (پنل با ورود خودش کار کند)؛ فقط noindex
|
|
env_set PREVIEW_MIDDLEWARES_API "preview-noindex@docker"
|
|
# در پیشنمایش، دامنه دوم به اصلی ریدایرکت نمیشود تا هر دو قابل بررسی باشند
|
|
env_set ALIAS_REDIRECT_MIDDLEWARES ""
|
|
echo "پیشنمایش خصوصی فعال شد — سایت آنلاین است، ورود با نام کاربری/رمز، بدون ایندکس."
|
|
echo "برای اعمال: bash scripts/stack.sh deploy-prod"
|
|
;;
|
|
|
|
off)
|
|
env_set PREVIEW_MODE off
|
|
env_set PREVIEW_MIDDLEWARES ""
|
|
env_set PREVIEW_MIDDLEWARES_API ""
|
|
# در انتشار، دامنه دوم به اصلی ریدایرکت میشود تا محتوای تکراری ایجاد نشود
|
|
env_set ALIAS_REDIRECT_MIDDLEWARES "to-primary@docker"
|
|
echo "حالت انتشار عمومی فعال شد — گیت ورود حذف و ایندکس مجاز میشود."
|
|
echo "پس از deploy، نقشه سایت را در Search Console ثبت کنید:"
|
|
echo " https://\$(grep '^DOMAIN=' .env | cut -d= -f2)/sitemap.xml"
|
|
echo "برای اعمال: bash scripts/stack.sh deploy-prod"
|
|
;;
|
|
|
|
status)
|
|
mode="$(env_get PREVIEW_MODE)"
|
|
mws="$(env_get PREVIEW_MIDDLEWARES)"
|
|
alias_mws="$(env_get ALIAS_REDIRECT_MIDDLEWARES)"
|
|
if [ "$mode" = "on" ]; then
|
|
echo "وضعیت: پیشنمایش خصوصی (آنلاین، غیرعمومی، noindex)"
|
|
elif [ "$mode" = "off" ]; then
|
|
echo "وضعیت: انتشار عمومی"
|
|
else
|
|
echo "وضعیت: تعییننشده (PREVIEW_MODE=${mode:-خالی}) — پیشفرض compose: off"
|
|
fi
|
|
echo " PREVIEW_MIDDLEWARES=${mws:-(خالی — بدون گیت)}"
|
|
echo " ALIAS_REDIRECT_MIDDLEWARES=${alias_mws:-(خالی — بدون ریدایرکت دامنه دوم)}"
|
|
if [ -n "$(env_get PREVIEW_AUTH_USERS)" ]; then
|
|
echo " کاربر پیشنمایش: $(env_get PREVIEW_AUTH_USERS | cut -d: -f1)"
|
|
else
|
|
echo " کاربر پیشنمایش: ساخته نشده (اولین «on» میسازد)"
|
|
fi
|
|
;;
|
|
|
|
*)
|
|
echo "استفاده: bash scripts/preview-mode.sh [on|off|status]" >&2
|
|
exit 1
|
|
;;
|
|
esac
|