Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e25294db16 | ||
|
|
a8d86e0c48 |
@@ -1,5 +1,6 @@
|
|||||||
# PZ Manager
|
# PZ Manager
|
||||||
|
|
||||||
|
[](https://gitea.hsrv.site/mrleo1nid/pzmanager/releases/latest)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](https://go.dev/)
|
[](https://go.dev/)
|
||||||
[](https://ubuntu.com/)
|
[](https://ubuntu.com/)
|
||||||
@@ -89,23 +90,25 @@ curl -fsSL https://gitea.hsrv.site/mrleo1nid/pzmanager/raw/branch/main/deploy/ge
|
|||||||
|
|
||||||
Дальше:
|
Дальше:
|
||||||
|
|
||||||
1. Посмотрите код первичной настройки:
|
1. Откройте панель в браузере и создайте администратора, введя код первичной
|
||||||
|
настройки — установщик печатает его последним сообщением. Если панель
|
||||||
```bash
|
слушает localhost, пробросьте порт:
|
||||||
journalctl -u pzmanager -n 30 --no-pager
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Откройте панель в браузере и создайте администратора, введя этот код.
|
|
||||||
Если панель слушает localhost, пробросьте порт:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh -L 8080:127.0.0.1:8080 пользователь@сервер
|
ssh -L 8080:127.0.0.1:8080 пользователь@сервер
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Во вкладке «Обзор» нажмите **Установить / обновить через SteamCMD** и
|
Код одноразовый и перестаёт работать сразу после создания администратора.
|
||||||
|
Если вывод установщика потерялся, код есть в журнале:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
journalctl -u pzmanager -n 30 --no-pager
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Во вкладке «Обзор» нажмите **Установить / обновить через SteamCMD** и
|
||||||
дождитесь окончания — прогресс виден во вкладке «Консоль».
|
дождитесь окончания — прогресс виден во вкладке «Консоль».
|
||||||
|
|
||||||
4. Запустите сервер. При первом запуске PZ создаст `Zomboid/Server/*.ini` —
|
3. Запустите сервер. При первом запуске PZ создаст `Zomboid/Server/*.ini` —
|
||||||
после этого станут доступны вкладки «Конфиг сервера», «Песочница» и «Моды».
|
после этого станут доступны вкладки «Конфиг сервера», «Песочница» и «Моды».
|
||||||
|
|
||||||
Порты, которые нужно открыть:
|
Порты, которые нужно открыть:
|
||||||
@@ -131,6 +134,32 @@ make build-linux
|
|||||||
sudo PZ_LISTEN=10.10.1.142:8080 ./deploy/install.sh
|
sudo PZ_LISTEN=10.10.1.142:8080 ./deploy/install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Удаление
|
||||||
|
|
||||||
|
Убрать панель, оставив миры и настройки:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo /opt/pzmanager/install.sh --uninstall
|
||||||
|
```
|
||||||
|
|
||||||
|
Удалить всё вместе с мирами, бэкапами и учётными записями:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo /opt/pzmanager/install.sh --uninstall --purge
|
||||||
|
```
|
||||||
|
|
||||||
|
`--purge` спрашивает подтверждение; в неинтерактивном запуске нужен ещё и
|
||||||
|
`--yes`. Каталог сносится, только если похож на установку панели — иначе
|
||||||
|
опечатка в `PZ_HOME` стоила бы чужих файлов.
|
||||||
|
|
||||||
|
Установщик кладёт свою копию в `/opt/pzmanager/install.sh`, так что для
|
||||||
|
удаления ничего скачивать не нужно. Если копии нет, те же аргументы принимает
|
||||||
|
и установочная команда:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://gitea.hsrv.site/mrleo1nid/pzmanager/raw/branch/main/deploy/get.sh | sudo bash -s -- --uninstall --purge
|
||||||
|
```
|
||||||
|
|
||||||
## Моды
|
## Моды
|
||||||
|
|
||||||
Project Zomboid хранит моды в двух строках конфига: `WorkshopItems` — что
|
Project Zomboid хранит моды в двух строках конфига: `WorkshopItems` — что
|
||||||
|
|||||||
@@ -131,10 +131,19 @@ func serve(cfg *config.Config, users *auth.Store, secureCookies bool) error {
|
|||||||
// Пока учёток нет, создать первого администратора можно только с этим
|
// Пока учёток нет, создать первого администратора можно только с этим
|
||||||
// кодом — иначе панель захватит любой, кто откроет её первым.
|
// кодом — иначе панель захватит любой, кто откроет её первым.
|
||||||
setupToken := ""
|
setupToken := ""
|
||||||
|
setupTokenFile := filepath.Join(cfg.DataDir, "setup-token")
|
||||||
if users.IsEmpty() {
|
if users.IsEmpty() {
|
||||||
setupToken = randomToken()
|
setupToken = randomToken()
|
||||||
|
// Код кладём и в файл: установщик читает его оттуда и показывает сразу
|
||||||
|
// после установки, не заставляя идти в журнал.
|
||||||
|
if err := os.WriteFile(setupTokenFile, []byte(setupToken+"\n"), 0o600); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "не удалось записать %s: %v\n", setupTokenFile, err)
|
||||||
|
}
|
||||||
fmt.Printf("\n Панель ещё не настроена.\n"+
|
fmt.Printf("\n Панель ещё не настроена.\n"+
|
||||||
" Откройте её в браузере и введите код первичной настройки:\n\n %s\n\n", setupToken)
|
" Откройте её в браузере и введите код первичной настройки:\n\n %s\n\n", setupToken)
|
||||||
|
} else {
|
||||||
|
// Панель уже настроена: файл мог остаться от прошлой установки.
|
||||||
|
os.Remove(setupTokenFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
apiServer := api.New(api.Options{
|
apiServer := api.New(api.Options{
|
||||||
@@ -148,6 +157,7 @@ func serve(cfg *config.Config, users *auth.Store, secureCookies bool) error {
|
|||||||
Static: static,
|
Static: static,
|
||||||
SecureCookies: secureCookies,
|
SecureCookies: secureCookies,
|
||||||
SetupToken: setupToken,
|
SetupToken: setupToken,
|
||||||
|
SetupTokenFile: setupTokenFile,
|
||||||
Repo: repoURL(),
|
Repo: repoURL(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
+37
-5
@@ -7,6 +7,15 @@
|
|||||||
#
|
#
|
||||||
# curl -fsSL .../get.sh | sudo PZ_LISTEN=10.10.1.142:8080 bash
|
# curl -fsSL .../get.sh | sudo PZ_LISTEN=10.10.1.142:8080 bash
|
||||||
#
|
#
|
||||||
|
# Удаление (аргументы уходят установщику как есть):
|
||||||
|
#
|
||||||
|
# curl -fsSL .../get.sh | sudo bash -s -- --uninstall
|
||||||
|
# curl -fsSL .../get.sh | sudo bash -s -- --uninstall --purge
|
||||||
|
#
|
||||||
|
# Если панель уже установлена, то же самое умеет её локальная копия:
|
||||||
|
#
|
||||||
|
# sudo /opt/pzmanager/install.sh --uninstall --purge
|
||||||
|
#
|
||||||
# Переменные окружения:
|
# Переменные окружения:
|
||||||
# PZ_VERSION какой тег ставить (по умолчанию последний релиз)
|
# PZ_VERSION какой тег ставить (по умолчанию последний релиз)
|
||||||
# PZ_HOME куда ставить (по умолчанию /opt/pzmanager)
|
# PZ_HOME куда ставить (по умолчанию /opt/pzmanager)
|
||||||
@@ -29,6 +38,19 @@ die() { echo "Ошибка: $*" >&2; exit 1; }
|
|||||||
|
|
||||||
[[ $EUID -eq 0 ]] || die "запустите с правами root (sudo)"
|
[[ $EUID -eq 0 ]] || die "запустите с правами root (sudo)"
|
||||||
|
|
||||||
|
# Аргументы уходят установщику. Для удаления бинарник качать незачем — это
|
||||||
|
# лишние восемь мегабайт ради скрипта, который его же и сотрёт.
|
||||||
|
ARGS=("$@")
|
||||||
|
NEED_BINARY=1
|
||||||
|
# Идиома ${ARGS[@]+...} нужна из-за set -u: обычная "${ARGS[@]:-}" на пустом
|
||||||
|
# массиве разворачивается в один пустой аргумент, и установщик спотыкается о
|
||||||
|
# него при обычной установке.
|
||||||
|
for arg in ${ARGS[@]+"${ARGS[@]}"}; do
|
||||||
|
case "$arg" in
|
||||||
|
--uninstall | --remove | --purge) NEED_BINARY=0 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
for tool in curl sha256sum; do
|
for tool in curl sha256sum; do
|
||||||
command -v "$tool" >/dev/null 2>&1 || die "не найдена утилита $tool"
|
command -v "$tool" >/dev/null 2>&1 || die "не найдена утилита $tool"
|
||||||
done
|
done
|
||||||
@@ -68,10 +90,13 @@ asset_url() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BIN_NAME="pzmanager-linux-${ARCH}"
|
BIN_NAME="pzmanager-linux-${ARCH}"
|
||||||
|
if [[ "$NEED_BINARY" == "1" ]]; then
|
||||||
BIN_URL="$(asset_url "$BIN_NAME")"
|
BIN_URL="$(asset_url "$BIN_NAME")"
|
||||||
[[ -n "$BIN_URL" ]] || die "в релизе ${TAG} нет файла ${BIN_NAME}"
|
[[ -n "$BIN_URL" ]] || die "в релизе ${TAG} нет файла ${BIN_NAME}"
|
||||||
|
|
||||||
echo "==> Ставлю ${TAG} (${ARCH})"
|
echo "==> Ставлю ${TAG} (${ARCH})"
|
||||||
|
else
|
||||||
|
echo "==> Беру установщик из ${TAG} для удаления"
|
||||||
|
fi
|
||||||
|
|
||||||
TMP="$(mktemp -d)"
|
TMP="$(mktemp -d)"
|
||||||
trap 'rm -rf "$TMP"' EXIT
|
trap 'rm -rf "$TMP"' EXIT
|
||||||
@@ -91,13 +116,17 @@ download() {
|
|||||||
curl -fsSL -o "$name" "$url" || die "не удалось скачать ${name}"
|
curl -fsSL -o "$name" "$url" || die "не удалось скачать ${name}"
|
||||||
}
|
}
|
||||||
|
|
||||||
download "$BIN_NAME"
|
|
||||||
download install.sh
|
download install.sh
|
||||||
download pzmanager.service
|
download pzmanager.service
|
||||||
|
FILES=(install.sh pzmanager.service)
|
||||||
|
|
||||||
|
if [[ "$NEED_BINARY" == "1" ]]; then
|
||||||
|
download "$BIN_NAME"
|
||||||
|
FILES+=("$BIN_NAME")
|
||||||
|
fi
|
||||||
|
|
||||||
# Скрипт привилегированных действий появился не сразу: со старым релизом
|
# Скрипт привилегированных действий появился не сразу: со старым релизом
|
||||||
# ставим без него, панель просто не покажет кнопку обновления.
|
# ставим без него, панель просто не покажет кнопку обновления.
|
||||||
FILES=("$BIN_NAME" install.sh pzmanager.service)
|
|
||||||
if download pzmanager-admin.sh optional; then
|
if download pzmanager-admin.sh optional; then
|
||||||
FILES+=(pzmanager-admin.sh)
|
FILES+=(pzmanager-admin.sh)
|
||||||
fi
|
fi
|
||||||
@@ -120,8 +149,11 @@ mv install.sh pzmanager.service deploy/
|
|||||||
if [[ -f pzmanager-admin.sh ]]; then
|
if [[ -f pzmanager-admin.sh ]]; then
|
||||||
mv pzmanager-admin.sh deploy/
|
mv pzmanager-admin.sh deploy/
|
||||||
fi
|
fi
|
||||||
|
chmod +x deploy/install.sh
|
||||||
|
if [[ "$NEED_BINARY" == "1" ]]; then
|
||||||
mv "$BIN_NAME" pzmanager
|
mv "$BIN_NAME" pzmanager
|
||||||
chmod +x pzmanager deploy/install.sh
|
chmod +x pzmanager
|
||||||
|
fi
|
||||||
|
|
||||||
echo "==> Запускаю установщик"
|
echo "==> Запускаю установщик"
|
||||||
BINARY="$TMP/pzmanager" bash deploy/install.sh
|
BINARY="$TMP/pzmanager" bash deploy/install.sh ${ARGS[@]+"${ARGS[@]}"}
|
||||||
|
|||||||
+123
-7
@@ -1,10 +1,12 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Установка и обновление pzmanager на Ubuntu/Debian. Запускать от root:
|
# Установка, обновление и удаление pzmanager на Ubuntu/Debian. От root:
|
||||||
#
|
#
|
||||||
# sudo ./deploy/install.sh
|
# sudo ./deploy/install.sh установить или обновить
|
||||||
|
# sudo ./deploy/install.sh --uninstall убрать панель, данные оставить
|
||||||
|
# sudo ./deploy/install.sh --uninstall --purge убрать вместе с мирами
|
||||||
#
|
#
|
||||||
# Скрипт идемпотентен: на уже настроенной машине он обновляет бинарник и
|
# Установка идемпотентна: на уже настроенной машине обновляются бинарник и
|
||||||
# юнит, не трогая конфиг, миры и учётные записи панели.
|
# юнит, а конфиг, миры и учётные записи панели остаются нетронутыми.
|
||||||
#
|
#
|
||||||
# Переменные окружения:
|
# Переменные окружения:
|
||||||
# PZ_HOME куда ставить всё хозяйство (по умолчанию /opt/pzmanager)
|
# PZ_HOME куда ставить всё хозяйство (по умолчанию /opt/pzmanager)
|
||||||
@@ -29,11 +31,94 @@ ADMIN_SRC="${SCRIPT_DIR}/pzmanager-admin.sh"
|
|||||||
TARGET_BINARY=/usr/local/bin/pzmanager
|
TARGET_BINARY=/usr/local/bin/pzmanager
|
||||||
ADMIN_BINARY=/usr/local/bin/pzmanager-admin
|
ADMIN_BINARY=/usr/local/bin/pzmanager-admin
|
||||||
|
|
||||||
|
UNINSTALL=0
|
||||||
|
PURGE=0
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--uninstall | --remove) UNINSTALL=1 ;;
|
||||||
|
--purge) UNINSTALL=1; PURGE=1 ;;
|
||||||
|
--yes | -y) PZ_ASSUME_YES=1 ;;
|
||||||
|
-h | --help)
|
||||||
|
sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Неизвестный аргумент: $arg" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
if [[ $EUID -ne 0 ]]; then
|
if [[ $EUID -ne 0 ]]; then
|
||||||
echo "Запустите скрипт от root: sudo $0" >&2
|
echo "Запустите скрипт от root: sudo $0" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# uninstall снимает панель с машины. Данные (миры, бэкапы, учётки) удаляются
|
||||||
|
# только по --purge: потерять сохранения из-за неудачно набранной команды
|
||||||
|
# гораздо обиднее, чем лишний раз убрать каталог руками.
|
||||||
|
uninstall() {
|
||||||
|
echo "==> Удаляю pzmanager"
|
||||||
|
|
||||||
|
if systemctl list-unit-files pzmanager.service &>/dev/null &&
|
||||||
|
systemctl is-active --quiet pzmanager; then
|
||||||
|
echo "==> Останавливаю службу (игровой сервер завершится штатно, это небыстро)"
|
||||||
|
systemctl stop pzmanager || true
|
||||||
|
fi
|
||||||
|
systemctl disable --quiet pzmanager 2>/dev/null || true
|
||||||
|
rm -f /etc/systemd/system/pzmanager.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl reset-failed pzmanager 2>/dev/null || true
|
||||||
|
|
||||||
|
rm -f /usr/local/bin/pzmanager /usr/local/bin/pzmanager-admin /etc/sudoers.d/pzmanager
|
||||||
|
echo "Служба, бинарники и правило sudo удалены."
|
||||||
|
|
||||||
|
if [[ "$PURGE" != "1" ]]; then
|
||||||
|
echo
|
||||||
|
echo "Данные остались в ${PZ_HOME} (миры, бэкапы, конфиг, учётные записи)."
|
||||||
|
echo "Удалить и их: sudo $0 --uninstall --purge"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Защита от опечатки в PZ_HOME: сносим только то, что похоже на нашу
|
||||||
|
# установку, и никогда — корень или домашние каталоги.
|
||||||
|
local home_clean="${PZ_HOME%/}"
|
||||||
|
if [[ -z "$home_clean" || "$home_clean" == "/" || "$home_clean" != /* ]]; then
|
||||||
|
echo "!! PZ_HOME=${PZ_HOME} не похож на каталог установки — не трогаю" >&2
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ ! -e "$home_clean/config.yaml" && ! -d "$home_clean/data" ]]; then
|
||||||
|
echo "!! В ${home_clean} нет ни config.yaml, ни data/ — не похоже на установку pzmanager," >&2
|
||||||
|
echo " поэтому каталог оставлен нетронутым." >&2
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${PZ_ASSUME_YES:-0}" != "1" ]]; then
|
||||||
|
echo
|
||||||
|
echo "Будет безвозвратно удалено: ${home_clean}"
|
||||||
|
echo "Это миры, бэкапы, конфиг и учётные записи панели."
|
||||||
|
if [[ -t 0 ]]; then
|
||||||
|
read -r -p "Введите YES для подтверждения: " answer
|
||||||
|
[[ "$answer" == "YES" ]] || { echo "Отменено."; return; }
|
||||||
|
else
|
||||||
|
echo "Запуск неинтерактивный — повторите с флагом --yes, если уверены." >&2
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf "$home_clean"
|
||||||
|
if id "$PZ_USER" &>/dev/null; then
|
||||||
|
deluser --system "$PZ_USER" &>/dev/null || userdel "$PZ_USER" &>/dev/null || true
|
||||||
|
echo "Пользователь ${PZ_USER} удалён."
|
||||||
|
fi
|
||||||
|
echo "Удалено полностью: ${home_clean}"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$UNINSTALL" == "1" ]]; then
|
||||||
|
uninstall
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ ! -f "$BINARY" ]]; then
|
if [[ ! -f "$BINARY" ]]; then
|
||||||
echo "Не найден бинарник $BINARY. Соберите его: make build-linux" >&2
|
echo "Не найден бинарник $BINARY. Соберите его: make build-linux" >&2
|
||||||
exit 1
|
exit 1
|
||||||
@@ -152,6 +237,14 @@ else
|
|||||||
echo "!! $ADMIN_SRC не найден или нет sudo — обновление из панели будет недоступно" >&2
|
echo "!! $ADMIN_SRC не найден или нет sudo — обновление из панели будет недоступно" >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Кладём сам установщик рядом с данными: удалить или переустановить панель
|
||||||
|
# можно будет одной локальной командой, без похода в репозиторий.
|
||||||
|
install -m 0755 "$0" "$PZ_HOME/install.sh"
|
||||||
|
if [[ -f "$ADMIN_SRC" ]]; then
|
||||||
|
install -m 0755 "$ADMIN_SRC" "$PZ_HOME/pzmanager-admin.sh"
|
||||||
|
fi
|
||||||
|
install -m 0644 "$UNIT_SRC" "$PZ_HOME/pzmanager.service"
|
||||||
|
|
||||||
echo "==> Ставлю systemd-юнит"
|
echo "==> Ставлю systemd-юнит"
|
||||||
sed -e "s|/opt/pzmanager|${PZ_HOME}|g" \
|
sed -e "s|/opt/pzmanager|${PZ_HOME}|g" \
|
||||||
-e "s|User=pzserver|User=${PZ_USER}|" \
|
-e "s|User=pzserver|User=${PZ_USER}|" \
|
||||||
@@ -178,8 +271,21 @@ if [[ "$MODE" == "update" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
systemctl start pzmanager
|
systemctl start pzmanager
|
||||||
# Дадим сервису секунду подняться, чтобы код настройки успел попасть в журнал.
|
|
||||||
sleep 2
|
# Панель кладёт код первичной настройки в файл, как только поднимется. Ждём
|
||||||
|
# его, чтобы показать код прямо здесь: иначе за ним пришлось бы идти в журнал.
|
||||||
|
SETUP_TOKEN=""
|
||||||
|
TOKEN_FILE="$PZ_HOME/data/setup-token"
|
||||||
|
for _ in $(seq 1 20); do
|
||||||
|
if [[ -s "$TOKEN_FILE" ]]; then
|
||||||
|
SETUP_TOKEN="$(head -1 "$TOKEN_FILE")"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if ! systemctl is-active --quiet pzmanager; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Готово. Панель запущена и слушает ${PZ_LISTEN}."
|
echo "Готово. Панель запущена и слушает ${PZ_LISTEN}."
|
||||||
@@ -198,8 +304,18 @@ else
|
|||||||
echo " sudo ufw allow ${PORT}/tcp"
|
echo " sudo ufw allow ${PORT}/tcp"
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
echo "Код первичной настройки — в журнале:"
|
if [[ -n "$SETUP_TOKEN" ]]; then
|
||||||
|
echo "Код первичной настройки (введите его в браузере):"
|
||||||
|
echo
|
||||||
|
echo " ${SETUP_TOKEN}"
|
||||||
|
echo
|
||||||
|
echo "Код одноразовый: после создания администратора он перестаёт работать."
|
||||||
|
else
|
||||||
|
echo "Код первичной настройки не удалось прочитать. Посмотрите журнал:"
|
||||||
echo
|
echo
|
||||||
echo " journalctl -u pzmanager -n 30 --no-pager"
|
echo " journalctl -u pzmanager -n 30 --no-pager"
|
||||||
|
fi
|
||||||
echo
|
echo
|
||||||
echo "Игровые порты сервера: udp/16261 и udp/16262."
|
echo "Игровые порты сервера: udp/16261 и udp/16262."
|
||||||
|
echo
|
||||||
|
echo "Удалить панель целиком: sudo ${PZ_HOME}/install.sh --uninstall --purge"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mrleo1nid/pzmanager/internal/auth"
|
"github.com/mrleo1nid/pzmanager/internal/auth"
|
||||||
@@ -55,6 +56,10 @@ func (s *Server) handleSetup(w http.ResponseWriter, r *http.Request) {
|
|||||||
writeError(w, http.StatusInternalServerError, err.Error())
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Администратор создан — код больше не нужен и не должен лежать на диске.
|
||||||
|
if s.setupTokenFile != "" {
|
||||||
|
os.Remove(s.setupTokenFile)
|
||||||
|
}
|
||||||
s.setSessionCookie(w, id, sessionTTL)
|
s.setSessionCookie(w, id, sessionTTL)
|
||||||
writeJSON(w, http.StatusOK, map[string]any{"authenticated": true, "login": creds.Login})
|
writeJSON(w, http.StatusOK, map[string]any{"authenticated": true, "login": creds.Login})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,8 +40,11 @@ type Server struct {
|
|||||||
// secureCookies включает флаг Secure у cookie сессии (панель за HTTPS).
|
// secureCookies включает флаг Secure у cookie сессии (панель за HTTPS).
|
||||||
secureCookies bool
|
secureCookies bool
|
||||||
// setupToken защищает первичное создание администратора: менеджер печатает
|
// setupToken защищает первичное создание администратора: менеджер печатает
|
||||||
// его в журнал при старте, когда учёток ещё нет.
|
// его при старте, когда учёток ещё нет.
|
||||||
setupToken string
|
setupToken string
|
||||||
|
// setupTokenFile — копия кода на диске, которую показывает установщик.
|
||||||
|
// После создания администратора файл больше не нужен.
|
||||||
|
setupTokenFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Options — то, что нужно собрать серверу API.
|
// Options — то, что нужно собрать серверу API.
|
||||||
@@ -57,6 +60,9 @@ type Options struct {
|
|||||||
Static fs.FS
|
Static fs.FS
|
||||||
SecureCookies bool
|
SecureCookies bool
|
||||||
SetupToken string
|
SetupToken string
|
||||||
|
// SetupTokenFile — файл с кодом первичной настройки, удаляется после
|
||||||
|
// создания администратора.
|
||||||
|
SetupTokenFile string
|
||||||
// Repo — репозиторий, из которого панель берёт обновления.
|
// Repo — репозиторий, из которого панель берёт обновления.
|
||||||
Repo string
|
Repo string
|
||||||
}
|
}
|
||||||
@@ -76,6 +82,7 @@ func New(o Options) *Server {
|
|||||||
static: o.Static,
|
static: o.Static,
|
||||||
secureCookies: o.SecureCookies,
|
secureCookies: o.SecureCookies,
|
||||||
setupToken: o.SetupToken,
|
setupToken: o.SetupToken,
|
||||||
|
setupTokenFile: o.SetupTokenFile,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user