Files
DragonCoreSSH-NewWEB/change_admin_password.sh
2026-05-02 23:20:13 -03:00

237 lines
6.6 KiB
Bash

#!/bin/bash
# DragonCoreSSH V40 admin password recovery tool.
# Usage:
# sudo bash change_admin_password.sh
# sudo bash change_admin_password.sh admin 'NewPasswordHere'
# sudo bash change_admin_password.sh --user admin --generate
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
info() { echo -e "${GREEN}[+]${NC} $*"; }
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
error() { echo -e "${RED}[x]${NC} $*"; exit 1; }
INSTALL_DIR="${INSTALL_DIR:-/opt/sshpanel}"
SERVICE_NAME="${SERVICE_NAME:-sshpanel}"
ENV_FILE="${ENV_FILE:-${INSTALL_DIR}/.env}"
ADMIN_USER=""
NEW_PASSWORD=""
GENERATE_PASSWORD=false
NO_RESTART=false
usage() {
cat <<USAGE
DragonCoreSSH V40 admin password recovery
Usage:
sudo bash $0
sudo bash $0 admin 'NewPasswordHere'
sudo bash $0 --user admin --password 'NewPasswordHere'
sudo bash $0 --user admin --generate
Options:
-u, --user USERNAME Admin username to reset. Default: admin
-p, --password PASSWORD New password. If omitted, you will be prompted.
-g, --generate Generate a strong random password.
--no-restart Do not restart the sshpanel service after changing DB.
-h, --help Show this help.
Environment overrides:
INSTALL_DIR=/opt/sshpanel
ENV_FILE=/opt/sshpanel/.env
SERVICE_NAME=sshpanel
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
-u|--user)
[[ $# -ge 2 ]] || error "Missing value for $1"
ADMIN_USER="$2"
shift 2
;;
-p|--password)
[[ $# -ge 2 ]] || error "Missing value for $1"
NEW_PASSWORD="$2"
shift 2
;;
-g|--generate)
GENERATE_PASSWORD=true
shift
;;
--no-restart)
NO_RESTART=true
shift
;;
-h|--help)
usage
exit 0
;;
--)
shift
break
;;
-* )
error "Unknown option: $1"
;;
*)
if [[ -z "$ADMIN_USER" ]]; then
ADMIN_USER="$1"
elif [[ -z "$NEW_PASSWORD" ]]; then
NEW_PASSWORD="$1"
else
error "Too many positional arguments. Use --help for usage."
fi
shift
;;
esac
done
[[ $EUID -ne 0 ]] && error "Run as root: sudo bash $0"
[[ -f "$ENV_FILE" ]] || error "Environment file not found: $ENV_FILE"
command -v psql >/dev/null 2>&1 || error "psql not found. Install PostgreSQL client first."
get_env_value() {
local key="$1"
awk -v key="$key" '
$0 ~ "^" key "=" {
sub("^[^=]*=", "")
gsub(/^\"|\"$/, "")
gsub(/^\047|\047$/, "")
print
exit
}
' "$ENV_FILE"
}
update_env_password() {
local new_password="$1"
local tmp
tmp="$(mktemp)"
awk -v line="ADMIN_PASSWORD=${new_password}" '
BEGIN { done = 0 }
/^ADMIN_PASSWORD=/ { print line; done = 1; next }
{ print }
END { if (!done) print line }
' "$ENV_FILE" > "$tmp"
cat "$tmp" > "$ENV_FILE"
rm -f "$tmp"
chmod 600 "$ENV_FILE" 2>/dev/null || true
}
generate_password() {
local pw=""
if command -v openssl >/dev/null 2>&1; then
pw="$(openssl rand -base64 24 | tr -d '\n' | tr -d '=/+' | head -c 24 || true)"
fi
if [[ ${#pw} -lt 20 ]]; then
pw="$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 24 || true)"
fi
if [[ ${#pw} -lt 20 ]]; then
pw="DragonCore$(date +%s%N)"
fi
printf '%s' "$pw"
}
hash_password() {
local pw="$1"
if command -v sha256sum >/dev/null 2>&1; then
printf '%s' "$pw" | sha256sum | awk '{print $1}'
elif command -v shasum >/dev/null 2>&1; then
printf '%s' "$pw" | shasum -a 256 | awk '{print $1}'
elif command -v openssl >/dev/null 2>&1; then
printf '%s' "$pw" | openssl dgst -sha256 -r | awk '{print $1}'
else
error "No SHA-256 tool found. Install coreutils or openssl."
fi
}
PG_DSN="$(get_env_value PG_DSN)"
[[ -n "$PG_DSN" ]] || error "PG_DSN not found inside $ENV_FILE"
if [[ -z "$ADMIN_USER" ]]; then
read -r -p "Admin username [admin]: " ADMIN_USER
ADMIN_USER="${ADMIN_USER:-admin}"
fi
[[ -n "$ADMIN_USER" ]] || error "Admin username cannot be empty."
if $GENERATE_PASSWORD; then
NEW_PASSWORD="$(generate_password)"
elif [[ -z "$NEW_PASSWORD" ]]; then
read -r -s -p "New password: " PASS1
echo
read -r -s -p "Confirm password: " PASS2
echo
[[ "$PASS1" == "$PASS2" ]] || error "Passwords do not match."
NEW_PASSWORD="$PASS1"
fi
[[ -n "$NEW_PASSWORD" ]] || error "Password cannot be empty."
if [[ ${#NEW_PASSWORD} -lt 8 ]]; then
error "Password must have at least 8 characters."
fi
PASSWORD_HASH="$(hash_password "$NEW_PASSWORD")"
[[ ${#PASSWORD_HASH} -eq 64 ]] || error "Failed to generate valid SHA-256 password hash."
info "Updating admin user '${ADMIN_USER}' in PostgreSQL..."
psql "$PG_DSN" -v ON_ERROR_STOP=1 \
-v admin_user="$ADMIN_USER" \
-v password_hash="$PASSWORD_HASH" <<'SQL'
CREATE TABLE IF NOT EXISTS admin_users (
id SERIAL PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'reseller',
max_users INT NOT NULL DEFAULT 30,
expires_at TIMESTAMPTZ,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
INSERT INTO admin_users (username, password_hash, role, max_users, expires_at, is_active)
VALUES (:'admin_user', :'password_hash', 'superadmin', 0, NULL, TRUE)
ON CONFLICT (username) DO UPDATE SET
password_hash = EXCLUDED.password_hash,
role = 'superadmin',
max_users = 0,
expires_at = NULL,
is_active = TRUE;
SQL
if [[ "$ADMIN_USER" == "admin" ]]; then
update_env_password "$NEW_PASSWORD"
info "Updated ADMIN_PASSWORD inside $ENV_FILE"
else
warn "ADMIN_PASSWORD in $ENV_FILE was not changed because username is not 'admin'."
fi
if ! $NO_RESTART; then
info "Restarting ${SERVICE_NAME} so the in-memory admin cache reloads..."
if command -v systemctl >/dev/null 2>&1 && systemctl list-unit-files "${SERVICE_NAME}.service" >/dev/null 2>&1; then
systemctl restart "$SERVICE_NAME"
sleep 1
if systemctl is-active --quiet "$SERVICE_NAME"; then
info "${SERVICE_NAME} restarted successfully."
else
warn "${SERVICE_NAME} is not active after restart. Last logs:"
journalctl -u "$SERVICE_NAME" -n 30 --no-pager 2>/dev/null || true
exit 1
fi
elif command -v service >/dev/null 2>&1; then
service "$SERVICE_NAME" restart || warn "Could not restart ${SERVICE_NAME}. Restart it manually."
else
warn "Could not restart ${SERVICE_NAME}. Restart it manually before logging in."
fi
else
warn "Service restart skipped. Restart ${SERVICE_NAME} manually before logging in."
fi
echo
info "Admin password changed."
echo " Username : ${ADMIN_USER}"
echo " Password : ${NEW_PASSWORD}"
echo
warn "Save this password now. It is only shown here."