diff --git a/deploy.sh b/deploy.sh index 87562af..243fce8 100755 --- a/deploy.sh +++ b/deploy.sh @@ -17,6 +17,45 @@ ssh_to_host() { ssh -i "${EXTRA_FILES_PATH}/home/numbus-admin/.ssh/id_ed25519" "${TARGET_USER}@${LIVE_TARGET_IP}" "${COMMAND}" } +get_valid_input() { + local VAR_NAME="${1}" + local HEADER="${2}" + local PLACEHOLDER="${3}" + local REGEX="${4}" + local MANDATORY="${5:-false}" + local SENSITIVE="${6:-false}" + + while true; do + local input + # --value pre-fills the input for easy editing + input=$(gum input --header "${HEADER}" --placeholder "${PLACEHOLDER}" --width 50) + + # Handle empty input + if [[ -z "$input" ]]; then + if [[ "$is_mandatory" == true ]]; then + gum style --foreground "#ff0000" -- "✖ This field is mandatory." + continue + else + return_var="" + break + fi + fi + + # Handle Regex Validation + if [[ -n "$regex" ]]; then + if [[ "$input" =~ $regex ]]; then + return_var="$input" + break + else + gum style --foreground "#ff0000" -- "✖ Invalid format. Please try again." + fi + else + return_var="$input" + break + fi + done +} + user_input() { local VAR_NAME="${1}" local HEADER="${2}" @@ -428,95 +467,30 @@ services_selection() { return 0 } +users_and_groups() { + declare -A ACL_GROUPS + declare -A ACL_USERS - - - - - - - - - - - - - - - - -############################################################################# -declare -A ACL_GROUPS -declare -A ACL_USERS - -ACL_SERVICES=() - -compute_acl_services() { - local all_services=("${SELECTED_DNS_SERVICE[@]}" "${SELECTED_WEB_APPLICATIONS[@]}" "${SELECTED_SYSTEM_SERVICES[@]}") - ACL_SERVICES=() # Reset to prevent duplicates on reload + compute_acl_services() { + EXCLUDED_SERVICES=( "clamav" ) # Those are the services that don't have a web page or don't support SSO + local ALL_SERVICES=("${SELECTED_DNS_SERVICE[@]}" "${SELECTED_WEB_APPLICATIONS[@]}" "${SELECTED_SYSTEM_SERVICES[@]}") - for svc in "${all_services[@]}"; do - local excluded=false - for ex in "${EXCLUDED_ACL_SERVICES[@]}"; do - if [[ "$svc" == "$ex" ]]; then - excluded=true - break - fi - done - if [[ "$excluded" == false ]]; then - ACL_SERVICES+=("$svc") + for i in "${!ALL_SERVICES[@]}"; do + for excluded in "${EXCLUDED_SERVICES[@]}"; do + if [[ "${ALL_SERVICES[${i}]}" == "${excluded}" ]]; then + unset "ALL_SERVICES[${i}]" fi + done done -} + } -# Upgraded to support default values for editing, and '--' for gum style -get_valid_input() { - local -n return_var=$1 - local prompt_text=$2 - local regex=$3 - local is_mandatory=$4 - local default_value=$5 - - while true; do - local val - # --value pre-fills the input for easy editing - val=$(gum input --prompt "$prompt_text: " --width 50 --value "$default_value") - - # Handle empty input - if [[ -z "$val" ]]; then - if [[ "$is_mandatory" == true ]]; then - gum style --foreground "#ff0000" -- "✖ This field is mandatory." - continue - else - return_var="" - break - fi - fi - - # Handle Regex Validation - if [[ -n "$regex" ]]; then - if [[ "$val" =~ $regex ]]; then - return_var="$val" - break - else - gum style --foreground "#ff0000" -- "✖ Invalid format. Please try again." - fi - else - return_var="$val" - break - fi - done -} -# ========================================== -# 4. GROUP MANAGEMENT -# ========================================== -show_groups_table() { + show_groups_table() { if [[ ${#ACL_GROUPS[@]} -eq 0 ]]; then - gum style --italic --foreground "#6272a4" -- "No groups configured." - return + gum style --italic --foreground "#6272a4" -- "No groups configured." + return fi # We use CSV format with quotes to handle comma-separated services correctly @@ -526,20 +500,20 @@ show_groups_table() { done printf "%b" "$csv" | gum table -} + } -add_group() { + add_group() { if [[ ${#ACL_GROUPS[@]} -ge 10 ]]; then - gum style --foreground "#ffb86c" -- "⚠ Maximum of 10 groups reached." - sleep 2; return + gum style --foreground "#ffb86c" -- "⚠ Maximum of 10 groups reached." + sleep 2; return fi local group_name get_valid_input group_name "Group Name" "^[a-zA-Z0-9_-]+$" true "" if [[ -n "${ACL_GROUPS[$group_name]}" ]]; then - gum style --foreground "#ff0000" -- "✖ Group already exists." - sleep 2; return + gum style --foreground "#ff0000" -- "✖ Group already exists." + sleep 2; return fi gum style --foreground "#50fa7b" -- "Select services for $group_name (Space to select, Enter to confirm):" @@ -549,9 +523,9 @@ add_group() { ACL_GROUPS["$group_name"]="$chosen_services" gum style --foreground "#50fa7b" -- "✔ Group '$group_name' created." sleep 1 -} + } -edit_group() { + edit_group() { if [[ ${#ACL_GROUPS[@]} -eq 0 ]]; then return; fi local group_keys=("${!ACL_GROUPS[@]}") @@ -570,9 +544,9 @@ edit_group() { ACL_GROUPS["$group_name"]="$chosen_services" gum style --foreground "#50fa7b" -- "✔ Group '$group_name' updated." sleep 1 -} + } -remove_group() { + remove_group() { if [[ ${#ACL_GROUPS[@]} -eq 0 ]]; then return; fi local group_keys=("${!ACL_GROUPS[@]}") @@ -581,65 +555,61 @@ remove_group() { if [[ -z "$group_name" ]]; then return; fi if [[ "$group_name" == "admin" ]]; then - gum style --foreground "#ff0000" -- "✖ The admin group cannot be removed." - sleep 2; return + gum style --foreground "#ff0000" -- "✖ The admin group cannot be removed." + sleep 2; return fi gum style --foreground "#ff5555" --bold -- "Are you sure you want to delete '$group_name'?" if gum confirm; then - unset ACL_GROUPS["$group_name"] - gum style --foreground "#50fa7b" -- "✔ Group deleted." - sleep 1 + unset ACL_GROUPS["$group_name"] + gum style --foreground "#50fa7b" -- "✔ Group deleted." + sleep 1 fi -} + } -manage_groups_menu() { + manage_groups_menu() { while true; do - clear - gum style --border double --margin "1" --padding "0 1" --border-foreground "#8be9fd" -- "Group Management (${#ACL_GROUPS[@]}/10)" - show_groups_table - - local action=$(gum choose "Add Group" "Edit Group" "Remove Group" "Back") - case "$action" in - "Add Group") add_group ;; - "Edit Group") edit_group ;; - "Remove Group") remove_group ;; - "Back"|"") break ;; - esac + clear + gum style --border double --margin "1" --padding "0 1" --border-foreground "#8be9fd" -- "Group Management (${#ACL_GROUPS[@]}/10)" + show_groups_table + + local action=$(gum choose "Add Group" "Edit Group" "Remove Group" "Back") + case "$action" in + "Add Group") add_group ;; + "Edit Group") edit_group ;; + "Remove Group") remove_group ;; + "Back"|"") break ;; + esac done -} + } -# ========================================== -# 5. USER MANAGEMENT -# ========================================== - -show_users_table() { + show_users_table() { if [[ ${#ACL_USERS[@]} -eq 0 ]]; then - gum style --italic --foreground "#6272a4" -- "No users configured." - return + gum style --italic --foreground "#6272a4" -- "No users configured." + return fi local csv="Username,Name,Email,Health Alerts,ACL Type,ACL Value\n" for u in "${!ACL_USERS[@]}"; do - IFS='|' read -r name email phone health type val <<< "${ACL_USERS[$u]}" - csv+="\"$u\",\"$name\",\"$email\",\"$health\",\"$type\",\"$val\"\n" + IFS='|' read -r name email phone health type input <<< "${ACL_USERS[$u]}" + csv+="\"$u\",\"$name\",\"$email\",\"$health\",\"$type\",\"$input\"\n" done printf "%b" "$csv" | gum table -} + } -add_user() { + add_user() { if [[ ${#ACL_USERS[@]} -ge 20 ]]; then - gum style --foreground "#ffb86c" -- "⚠ Maximum of 20 users reached." - sleep 2; return + gum style --foreground "#ffb86c" -- "⚠ Maximum of 20 users reached." + sleep 2; return fi local name username email phone health_alert acl_type acl_value get_valid_input username "Username" "^[a-z0-9_-]+$" true "" if [[ -n "${ACL_USERS[$username]}" ]]; then - gum style --foreground "#ff0000" -- "✖ Username already exists." - sleep 2; return + gum style --foreground "#ff0000" -- "✖ Username already exists." + sleep 2; return fi get_valid_input name "Full Name" "" true "" @@ -653,21 +623,21 @@ add_user() { acl_type=$(gum choose "Assign to Group" "Manual Service Selection") if [[ "$acl_type" == "Assign to Group" ]]; then - acl_type="group" - local group_keys=("${!ACL_GROUPS[@]}") - acl_value=$(gum choose "${group_keys[@]}") + acl_type="group" + local group_keys=("${!ACL_GROUPS[@]}") + acl_value=$(gum choose "${group_keys[@]}") else - acl_type="manual" - gum style --foreground "#50fa7b" -- "Select services for $username:" - acl_value=$(gum choose --no-limit "${ACL_SERVICES[@]}" | paste -sd "," -) + acl_type="manual" + gum style --foreground "#50fa7b" -- "Select services for $username:" + acl_value=$(gum choose --no-limit "${ACL_SERVICES[@]}" | paste -sd "," -) fi ACL_USERS["$username"]="$name|$email|$phone|$health_alert|$acl_type|$acl_value" gum style --foreground "#50fa7b" -- "✔ User '$username' created." sleep 1 -} + } -edit_user() { + edit_user() { if [[ ${#ACL_USERS[@]} -eq 0 ]]; then return; fi local user_keys=("${!ACL_USERS[@]}") @@ -686,35 +656,35 @@ edit_user() { get_valid_input phone "Phone Number" "$PHONE_REGEX" false "$curr_phone" if [[ "$username" == "admin" ]]; then - gum style --foreground "#ffb86c" -- "Admin health alerts and ACL settings cannot be changed." - health_alert="true" - acl_type="group" - acl_value="admin" - sleep 2 + gum style --foreground "#ffb86c" -- "Admin health alerts and ACL settings cannot be changed." + health_alert="true" + acl_type="group" + acl_value="admin" + sleep 2 else - gum style -- "Inform about server health? (Currently: $curr_health)" - if gum confirm; then health_alert="true"; else health_alert="false"; fi + gum style -- "Inform about server health? (Currently: $curr_health)" + if gum confirm; then health_alert="true"; else health_alert="false"; fi gum style -- "How should ACL be managed? (Currently: $curr_type)" acl_type=$(gum choose "Assign to Group" "Manual Service Selection") if [[ "$acl_type" == "Assign to Group" ]]; then - acl_type="group" - local group_keys=("${!ACL_GROUPS[@]}") - acl_value=$(gum choose "${group_keys[@]}") + acl_type="group" + local group_keys=("${!ACL_GROUPS[@]}") + acl_value=$(gum choose "${group_keys[@]}") else - acl_type="manual" - gum style --foreground "#50fa7b" -- "Select services for $username:" - acl_value=$(gum choose --no-limit "${ACL_SERVICES[@]}" | paste -sd "," -) + acl_type="manual" + gum style --foreground "#50fa7b" -- "Select services for $username:" + acl_value=$(gum choose --no-limit "${ACL_SERVICES[@]}" | paste -sd "," -) fi - fi - - ACL_USERS["$username"]="$name|$email|$phone|$health_alert|$acl_type|$acl_value" - gum style --foreground "#50fa7b" -- "✔ User '$username' updated." - sleep 1 -} + fi + + ACL_USERS["$username"]="$name|$email|$phone|$health_alert|$acl_type|$acl_value" + gum style --foreground "#50fa7b" -- "✔ User '$username' updated." + sleep 1 + } -remove_user() { + remove_user() { if [[ ${#ACL_USERS[@]} -eq 0 ]]; then return; fi local user_keys=("${!ACL_USERS[@]}") @@ -723,39 +693,35 @@ remove_user() { if [[ -z "$username" ]]; then return; fi if [[ "$username" == "admin" ]]; then - gum style --foreground "#ff0000" -- "✖ The admin user cannot be removed." - sleep 2; return + gum style --foreground "#ff0000" -- "✖ The admin user cannot be removed." + sleep 2; return fi gum style --foreground "#ff5555" --bold -- "Are you sure you want to delete '$username'?" if gum confirm; then - unset ACL_USERS["$username"] - gum style --foreground "#50fa7b" -- "✔ User deleted." - sleep 1 + unset ACL_USERS["$username"] + gum style --foreground "#50fa7b" -- "✔ User deleted." + sleep 1 fi -} + } -manage_users_menu() { + manage_users_menu() { while true; do - clear - gum style --border double --margin "1" --padding "0 1" --border-foreground "#ff79c6" -- "User Management (${#ACL_USERS[@]}/20)" - show_users_table - - local action=$(gum choose "Add User" "Edit User" "Remove User" "Back") - case "$action" in - "Add User") add_user ;; - "Edit User") edit_user ;; - "Remove User") remove_user ;; - "Back"|"") break ;; - esac + clear + gum style --border double --margin "1" --padding "0 1" --border-foreground "#ff79c6" -- "User Management (${#ACL_USERS[@]}/20)" + show_users_table + + local action=$(gum choose "Add User" "Edit User" "Remove User" "Back") + case "$action" in + "Add User") add_user ;; + "Edit User") edit_user ;; + "Remove User") remove_user ;; + "Back"|"") break ;; + esac done -} + } -# ========================================== -# 6. SETUP & EXPORT -# ========================================== - -setup_admin_user() { + setup_admin_user() { if [[ -n "${ACL_USERS["admin"]}" ]]; then return; fi gum style --border rounded --padding "1 2" --margin "1" --border-foreground "#ff79c6" -- "Initial Setup: Administrator User" @@ -768,9 +734,9 @@ setup_admin_user() { ACL_USERS["admin"]="$name|$email|$phone|true|group|admin" gum style --foreground "#50fa7b" -- "✔ Administrator configured." sleep 1 -} + } -export_data() { + export_data() { clear gum style --foreground "#50fa7b" --bold -- "--- Provisioning Data Payload ---" echo "GROUPS:" @@ -782,54 +748,31 @@ export_data() { for user in "${!ACL_USERS[@]}"; do echo " $user -> ${ACL_USERS[$user]}" done + } + + compute_acl_services + ACL_GROUPS["admin"]=$(printf "%s," "${ACL_SERVICES[@]}" | sed 's/,$//') + setup_admin_user + + while true; do + clear + gum style --border double --margin "1" --padding "1 2" --border-foreground "#bd93f9" -- "Numbus Deployment - Access Management" + gum style -- "Current state: ${#ACL_GROUPS[@]}/10 Groups | ${#ACL_USERS[@]}/20 Users" + echo "" + + local choice=$(gum choose "1. Manage Groups" "2. Manage Users" "3. Finish & Apply Configuration") + + case "$choice" in + "1. Manage Groups") manage_groups_menu ;; + "2. Manage Users") manage_users_menu ;; + "3. Finish & Apply Configuration") + export_data + break + ;; + esac + done } -main_menu() { - compute_acl_services - ACL_GROUPS["admin"]=$(printf "%s," "${ACL_SERVICES[@]}" | sed 's/,$//') - setup_admin_user - - while true; do - clear - gum style --border double --margin "1" --padding "1 2" --border-foreground "#bd93f9" -- "Server Deployment - Access Management" - gum style -- "Current state: ${#ACL_GROUPS[@]}/10 Groups | ${#ACL_USERS[@]}/20 Users" - echo "" - - local choice=$(gum choose "1. Manage Groups" "2. Manage Users" "3. Finish & Apply Configuration" "4. Exit without saving") - - case "$choice" in - "1. Manage Groups") manage_groups_menu ;; - "2. Manage Users") manage_users_menu ;; - "3. Finish & Apply Configuration") - export_data - break - ;; - "4. Exit without saving"|"") - echo "Aborting..." - exit 1 - ;; - esac - done -} - - -########################################################################"" - - - - - - - - - - - - - - - - disks_selection() { gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 " ⚠️ $(gum style --foreground 212 'WARNING:') You will choose the disks to install NixOS on. @@ -1399,6 +1342,8 @@ EMAIL_REGEX='^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' PORT_REGEX='^[0-9]{1,5}$' SSH_KEY_REGEX='^ssh-[a-z0-9]+ [A-Za-z0-9+/]+.*' PHONE_REGEX='^\+[1-9][0-9]{7,14}$' + + # --- DEFAULTS VARIABLES ---<