|
@@ -535,12 +535,13 @@ manage_users_and_roles() {
|
|
|
while true; do
|
|
while true; do
|
|
|
$DIALOG --clear \
|
|
$DIALOG --clear \
|
|
|
--title "Manage Users & Roles" \
|
|
--title "Manage Users & Roles" \
|
|
|
- --menu "Choose an action:" 17 60 6 \
|
|
|
|
|
|
|
+ --menu "Choose an action:" 18 60 7 \
|
|
|
1 "Create a role" \
|
|
1 "Create a role" \
|
|
|
2 "Create a user" \
|
|
2 "Create a user" \
|
|
|
3 "Delete a role" \
|
|
3 "Delete a role" \
|
|
|
4 "Delete a user" \
|
|
4 "Delete a user" \
|
|
|
- 5 "Back to main menu" 2>"$CHOICE_FILE"
|
|
|
|
|
|
|
+ 5 "Change user password" \
|
|
|
|
|
+ 6 "Back to main menu" 2>"$CHOICE_FILE"
|
|
|
|
|
|
|
|
[[ ! -s "$CHOICE_FILE" ]] && return 0
|
|
[[ ! -s "$CHOICE_FILE" ]] && return 0
|
|
|
choice=$(<"$CHOICE_FILE")
|
|
choice=$(<"$CHOICE_FILE")
|
|
@@ -550,7 +551,8 @@ manage_users_and_roles() {
|
|
|
2) create_user ;;
|
|
2) create_user ;;
|
|
|
3) delete_role ;;
|
|
3) delete_role ;;
|
|
|
4) delete_user ;;
|
|
4) delete_user ;;
|
|
|
- 5) return 0 ;;
|
|
|
|
|
|
|
+ 5) change_user_password ;;
|
|
|
|
|
+ 6) return 0 ;;
|
|
|
esac
|
|
esac
|
|
|
done
|
|
done
|
|
|
}
|
|
}
|
|
@@ -780,6 +782,85 @@ delete_user() {
|
|
|
$DIALOG --msgbox "User '$selected_username' deleted successfully!" 8 60
|
|
$DIALOG --msgbox "User '$selected_username' deleted successfully!" 8 60
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+change_user_password() {
|
|
|
|
|
+ # Fetch users from the database
|
|
|
|
|
+ local users_list
|
|
|
|
|
+ users_list=$(db_query "SELECT id, username, name FROM users ORDER BY id;" "$DB_TARGET" 2>>"$LOG_FILE") || {
|
|
|
|
|
+ $DIALOG --msgbox "Failed to fetch users from database." 10 60
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # Build user selection menu
|
|
|
|
|
+ local user_options=()
|
|
|
|
|
+ while IFS=$'\t' read -r user_id username name; do
|
|
|
|
|
+ user_options+=("$user_id" "$username - $name")
|
|
|
|
|
+ done <<< "$users_list"
|
|
|
|
|
+
|
|
|
|
|
+ if [[ ${#user_options[@]} -eq 0 ]]; then
|
|
|
|
|
+ $DIALOG --msgbox "No users found in database." 10 60
|
|
|
|
|
+ return
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # Select user
|
|
|
|
|
+ $DIALOG --menu "Select user to change password:" 20 70 10 "${user_options[@]}" 2>"$TMP_FILE" || return
|
|
|
|
|
+ local selected_user_id
|
|
|
|
|
+ selected_user_id=$(<"$TMP_FILE")
|
|
|
|
|
+
|
|
|
|
|
+ # Get username for display
|
|
|
|
|
+ local selected_username
|
|
|
|
|
+ selected_username=$(echo "$users_list" | awk -v id="$selected_user_id" -F'\t' '$1 == id {print $2}')
|
|
|
|
|
+
|
|
|
|
|
+ # Get new password
|
|
|
|
|
+ $DIALOG --passwordbox "Enter new password for user '$selected_username':" 10 60 2>"$TMP_FILE" || return
|
|
|
|
|
+ local new_password
|
|
|
|
|
+ new_password=$(<"$TMP_FILE")
|
|
|
|
|
+
|
|
|
|
|
+ if [[ -z "$new_password" ]]; then
|
|
|
|
|
+ $DIALOG --msgbox "Password cannot be empty." 8 50
|
|
|
|
|
+ return
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # Hash password with bcrypt (cost 12) and avoid set -e aborts
|
|
|
|
|
+ local password_hash status
|
|
|
|
|
+ status=1
|
|
|
|
|
+
|
|
|
|
|
+ # Try htpasswd first (native Unix tool)
|
|
|
|
|
+ if command -v htpasswd >/dev/null 2>&1; then
|
|
|
|
|
+ set +e
|
|
|
|
|
+ password_hash=$(htpasswd -nbB -C 12 "$selected_username" "$new_password" 2>>"$LOG_FILE")
|
|
|
|
|
+ status=$?
|
|
|
|
|
+ set -e
|
|
|
|
|
+ password_hash=$(echo "$password_hash" | cut -d: -f2)
|
|
|
|
|
+ # Fall back to Python bcrypt
|
|
|
|
|
+ elif command -v python3 >/dev/null 2>&1; then
|
|
|
|
|
+ set +e
|
|
|
|
|
+ password_hash=$(python3 - "$new_password" "$selected_username" 2>>"$LOG_FILE" <<'PY'
|
|
|
|
|
+import sys, bcrypt
|
|
|
|
|
+pw = sys.argv[1]
|
|
|
|
|
+print(bcrypt.hashpw(pw.encode('utf-8'), bcrypt.gensalt(12)).decode('utf-8'))
|
|
|
|
|
+PY
|
|
|
|
|
+)
|
|
|
|
|
+ status=$?
|
|
|
|
|
+ set -e
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if [[ $status -ne 0 || -z "$password_hash" ]]; then
|
|
|
|
|
+ $DIALOG --msgbox "Error: Failed to hash password.\n\nInstall one of these:\n- htpasswd: brew install httpd (macOS) or apt install apache2-utils (Linux)\n- Python bcrypt: pip3 install bcrypt" 12 70
|
|
|
|
|
+ return
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # Update password
|
|
|
|
|
+ local sql="UPDATE users SET password = '$password_hash' WHERE id = $selected_user_id;"
|
|
|
|
|
+
|
|
|
|
|
+ db_exec_sql "$sql" "$DB_TARGET" >>"$LOG_FILE" 2>&1 || {
|
|
|
|
|
+ error_log=$(tail -20 "$LOG_FILE")
|
|
|
|
|
+ $DIALOG --title "Error" --msgbox "Failed to change password.\n\nError:\n${error_log}" 20 76
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $DIALOG --msgbox "Password for user '$selected_username' changed successfully!" 8 60
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
clone_if_missing() {
|
|
clone_if_missing() {
|
|
|
local repo_url="$1" dest_dir="$2"
|
|
local repo_url="$1" dest_dir="$2"
|
|
|
if [[ -d "$dest_dir/.git" ]]; then
|
|
if [[ -d "$dest_dir/.git" ]]; then
|