From c9670e36d664975b09ad7957f58626fe3bcc1802 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Wed, 27 May 2026 23:32:42 +0200 Subject: [PATCH] fix(install): address Copilot review on Postgres install flow - Use mktemp (unguessable, 0600) instead of /tmp/x-ui-pg-creds.$$ and cleanup in both success and failure paths to close the symlink/race attack on the predictable filename. - In install_postgres_local, capture the prior umask and restore it after writing PG_CRED_FILE; return 1 if the write fails so the caller does not source nothing and label the install with empty PG_* vars. - On reinstall, reuse the existing xui DB owner instead of generating a fresh role each run, so existing tables stay accessible after a re-run; only the password is rotated. Falls back to a fresh random role when the DB does not exist or is owned by postgres. --- install.sh | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/install.sh b/install.sh index c65b9963..2d555944 100644 --- a/install.sh +++ b/install.sh @@ -112,7 +112,6 @@ gen_random_string() { install_postgres_local() { local pg_user pg_pass - pg_user=$(gen_random_string 8) pg_pass=$(gen_random_string 24) local pg_db="xui" local pg_host="127.0.0.1" @@ -172,6 +171,16 @@ install_postgres_local() { sleep 1 done + local existing_owner="" + existing_owner=$(sudo -u postgres psql -tAc \ + "SELECT pg_catalog.pg_get_userbyid(datdba) FROM pg_database WHERE datname='${pg_db}'" 2> /dev/null \ + | tr -d '[:space:]') + if [[ -n "${existing_owner}" && "${existing_owner}" != "postgres" ]]; then + pg_user="${existing_owner}" + else + pg_user=$(gen_random_string 8) + fi + # Idempotent role/db creation. Identifiers are double-quoted because a # random username may start with a digit, which Postgres rejects unquoted. sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='${pg_user}'" 2> /dev/null \ @@ -188,15 +197,21 @@ install_postgres_local() { pg_pass_enc=$(printf '%s' "${pg_pass}" | sed -e 's/%/%25/g' -e 's/:/%3A/g' -e 's/@/%40/g' -e 's|/|%2F|g' -e 's/?/%3F/g' -e 's/#/%23/g') if [[ -n "${PG_CRED_FILE:-}" ]]; then + local prev_umask + prev_umask=$(umask) umask 077 - cat > "${PG_CRED_FILE}" < "${PG_CRED_FILE}" << EOF; then PG_USER=${pg_user} PG_PASS=${pg_pass} PG_HOST=${pg_host} PG_PORT=${pg_port} PG_DB=${pg_db} EOF - umask 022 + umask "${prev_umask}" + echo -e "${red}Failed to write PostgreSQL credentials to ${PG_CRED_FILE}${plain}" >&2 + return 1 + fi + umask "${prev_umask}" fi echo "postgres://${pg_user}:${pg_pass_enc}@${pg_host}:${pg_port}/${pg_db}?sslmode=disable" @@ -875,17 +890,22 @@ config_after_install() { else echo -e "${yellow}Installing PostgreSQL — this may take a moment...${plain}" local pg_cred_file - pg_cred_file="/tmp/x-ui-pg-creds.$$" - rm -f "${pg_cred_file}" + pg_cred_file=$(mktemp 2> /dev/null) || pg_cred_file=$(mktemp -t x-ui-pg-creds.XXXXXXXX) + if [[ -z "${pg_cred_file}" ]]; then + echo -e "${red}Failed to create temporary credentials file.${plain}" + xui_dsn="" + continue + fi if xui_dsn=$(PG_CRED_FILE="${pg_cred_file}" install_postgres_local); then pg_local_installed=1 if [[ -r "${pg_cred_file}" ]]; then # shellcheck disable=SC1090 source "${pg_cred_file}" - rm -f "${pg_cred_file}" fi + rm -f "${pg_cred_file}" db_label="PostgreSQL (${PG_USER}@${PG_HOST}:${PG_PORT}/${PG_DB})" else + rm -f "${pg_cred_file}" echo "" echo -e "${red}PostgreSQL installation failed.${plain}" echo -e " 1) Retry local install"