version: 0.6 id: addsftp type: update description: An addon to add new SFTP users for Jelastic Virtuozzo LLSMP environments. It manages user accounts with secure SFTP access and optional SSH access with proper chroot jailing. name: Add SFTP User for Jelastic targetNodes: nodeGroup: cp settings: sfpform: submitUnchanged: true fields: - type: displayfield name: infoField caption: Root Directory /var/www/webroot/ROOT/ description: "Files will be accessible in a data/ROOT directory within the user's home" required: false - type: string name: custom_username caption: Custom Username description: "Enter a custom username (3-32 characters, alphanumeric + underscore only)" required: true regex: ^[a-zA-Z0-9_]{3,32}$ regexText: "Username must be 3-32 characters long and contain only letters, numbers, and underscores" - type: checkbox name: allow caption: Accept User Creation default: false required: false - type: checkbox name: enable_ssh caption: Also enable SSH access default: false required: false tip: "If enabled, the user will have both SFTP and SSH access. Otherwise, only SFTP access will be granted." manageUserForm: fields: - type: string name: manage_username caption: Username to Manage description: "Enter the username you want to manage." required: true regex: ^[a-zA-Z0-9_]{3,32}$ regexText: "Username must be 3-32 characters long and contain only letters, numbers, and underscores" - type: string name: custom_password caption: New Password description: "Enter a new password for the user (leave empty to generate random password)" required: false deleteUserForm: fields: - type: string name: manage_username caption: Username to Delete description: "Enter the username you want to delete." required: true regex: ^[a-zA-Z0-9_]{3,32}$ regexText: "Username must be 3-32 characters long and contain only letters, numbers, and underscores" globals: username: ${settings.custom_username} password: ${fn.password(min)} sftpHost: ${env.domain} sftpPort: 22 onInstall: - cmd[cp]: user: root commands: |- # Create required directories and files mkdir -p /home/jelastic/add-sftp-user-addon/logs/{operations,errors,debug} chmod -R 755 /home/jelastic/add-sftp-user-addon/logs touch /home/jelastic/add-sftp-user-addon/logs/script_output.log chmod 644 /home/jelastic/add-sftp-user-addon/logs/script_output.log # Download scripts wget https://deploy-proxy.mightybox.io/addons/add-sftp-user/raw/branch/main/add-sftp.sh -O /home/jelastic/add-sftp-user-addon/add-sftp.sh wget https://deploy-proxy.mightybox.io/addons/add-sftp-user/raw/branch/main/log_helper.sh -O /home/jelastic/add-sftp-user-addon/log_helper.sh chmod +x /home/jelastic/add-sftp-user-addon/add-sftp.sh chmod +x /home/jelastic/add-sftp-user-addon/log_helper.sh # Very important - fix /home directory permissions for SFTP chroot echo "$(date) - Checking and fixing /home directory permissions for SFTP chroot" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log # Get current /home permissions current_owner=$(stat -c "%U:%G" /home) current_perms=$(stat -c "%a" /home) echo "Current /home ownership: $current_owner, permissions: $current_perms" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log # Fix ownership and permissions chown root:root /home chmod 755 /home echo "Fixed /home ownership to root:root with 755 permissions" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log echo "$(date) - Installing SFTP addon on Jelastic environment" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log - cmd[cp]: user: root commands: |- # Create backup of original sshd_config cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d%H%M%S) echo "Created backup of original sshd_config" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log # Fix SFTP subsystem configuration if grep -q "Subsystemsftp" /etc/ssh/sshd_config; then sed -i 's|Subsystemsftp/usr/libexec/openssh/sftp-server|Subsystem sftp /usr/libexec/openssh/sftp-server|g' /etc/ssh/sshd_config echo "Fixed malformed SFTP subsystem configuration" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log fi # Enable password authentication globally if it's set to no if grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config; then sed -i 's/^PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config echo "Enabled global password authentication" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log fi # Configure SFTP chroot jail if ! grep -q "^Match Group sftpusers" /etc/ssh/sshd_config; then echo -e "\n# SFTP chroot configuration for Jelastic Virtuozzo\nMatch Group sftpusers\n ChrootDirectory /home/sftpusers/%u\n ForceCommand internal-sftp\n PasswordAuthentication yes\n AllowTcpForwarding no\n X11Forwarding no" >> /etc/ssh/sshd_config echo "Added SFTP chroot configuration" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log fi # Create sftpusers group and directory groupadd -f sftpusers mkdir -p /home/sftpusers chown root:root /home/sftpusers chmod 755 /home/sftpusers echo "Created sftpusers group and directory with proper permissions" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log # Clean up configuration - remove duplicate lines awk '!seen[$0]++' /etc/ssh/sshd_config > /etc/ssh/sshd_config.tmp && mv /etc/ssh/sshd_config.tmp /etc/ssh/sshd_config echo "Cleaned up sshd_config file" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log # Verify configuration if sshd -t; then echo "SSH configuration is valid, applying changes" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log systemctl restart sshd else echo "ERROR: SSH configuration is INVALID, reverting to backup" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log cp /etc/ssh/sshd_config.bak.$(ls -t /etc/ssh/sshd_config.bak.* | head -1 | awk -F/ '{print $NF}') /etc/ssh/sshd_config systemctl restart sshd fi - cmd[cp]: user: root commands: - systemctl restart sshd - api: environment.control.RestartContainer nodeGroup: cp nodeid: ${nodes.cp.id} - return: installSuccess menu: confirmText: "Do you want to list all users?" loadingText: "Loading users..." action: "list_users" caption: "List Users" successText: "Users listed successfully!" logsNodeGroup: cp actions: add_sftp_user: - if ('${settings.enable_ssh}' == 'true'): setGlobals: ssh_enabled: "true" - if ('${settings.enable_ssh}' != 'true'): setGlobals: ssh_enabled: "false" - cmd[cp]: user: root commands: |- # Run the script directly capturing only the variables we need OUTPUT_LOG="/home/jelastic/add-sftp-user-addon/logs/user_creation-$(date +%Y%m%d%H%M%S).log" touch "$OUTPUT_LOG" # Run the script with all output going to the log file bash /home/jelastic/add-sftp-user-addon/add-sftp.sh ${globals.username} ${globals.password} ${globals.ssh_enabled} > "$OUTPUT_LOG" 2>&1 # Export only username - no other output if [ -n "$CREATED_USERNAME" ]; then echo "$CREATED_USERNAME" else # Fallback to the original username if variable not set echo "${globals.username}" fi - setGlobals: username: ${response.out} - cmd[cp]: user: root commands: |- # Export only password - no other output if [ -n "$CREATED_PASSWORD" ]; then echo "$CREATED_PASSWORD" else # Fallback to the original password if variable not set echo "${globals.password}" fi - setGlobals: password: ${response.out} - return: type: info message: "Connection Details\n\nSFTP Host: ${globals.sftpHost}\n\nPort: ${globals.sftpPort}\n\nLogin Credentials\n\nUsername: ${globals.username}\n\nPassword: ${globals.password}\n\nNotes:\n- Files are accessible at /data/ROOT inside your SFTP session\n- If you enabled SSH access, you can also log in via SSH" change_password: # Verify user exists - cmd[cp]: user: root commands: |- # Create log file for this run LOG_FILE="/home/jelastic/add-sftp-user-addon/logs/password_change.log" touch "$LOG_FILE" # Source the logging helper source /home/jelastic/add-sftp-user-addon/log_helper.sh # Log start of process log_message "INFO" "======== STARTING PASSWORD CHANGE ========" "password_change.log" log_message "INFO" "Verifying user exists: ${settings.manage_username}" "password_change.log" # Check if user exists if id ${settings.manage_username} &>/dev/null; then log_message "INFO" "User ${settings.manage_username} exists" "password_change.log" exit 0 else log_message "ERROR" "User ${settings.manage_username} does not exist" "password_change.log" echo "User does not exist" exit 1 fi - if ("${response.exitStatus}" != "0"): return: type: error message: "User ${settings.manage_username} does not exist." # Use custom password if provided, otherwise generate one - if ('${settings.custom_password}' != ''): setGlobals: password: ${settings.custom_password} - if ('${settings.custom_password}' == ''): setGlobals: password: ${fn.password(12)} # Update password - cmd[cp]: user: root commands: |- # Source the logging helper source /home/jelastic/add-sftp-user-addon/log_helper.sh log_message "INFO" "Changing password for user: ${settings.manage_username}" "password_change.log" # Change password using echo and chpasswd if echo "${settings.manage_username}:${globals.password}" | /usr/sbin/chpasswd; then log_message "SUCCESS" "Password changed successfully for ${settings.manage_username}" "password_change.log" echo "Password changed for ${settings.manage_username} at $(date)" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log exit 0 else log_message "ERROR" "Failed to change password for ${settings.manage_username}" "password_change.log" exit 1 fi log_message "SUCCESS" "======== PASSWORD CHANGE COMPLETED ========" "password_change.log" - if ("${response.exitStatus}" != "0"): return: passwordChangeError - return: passwordChangeSuccess delete_user: # Verify user exists first - cmd[cp]: user: root commands: |- # Create log file for this run LOG_FILE="/home/jelastic/add-sftp-user-addon/logs/user_deletion.log" touch "$LOG_FILE" # Source the logging helper source /home/jelastic/add-sftp-user-addon/log_helper.sh # Log start of process log_message "INFO" "======== STARTING USER DELETION ========" "user_deletion.log" log_message "INFO" "Verifying user exists: ${settings.manage_username}" "user_deletion.log" # Check if user exists if id ${settings.manage_username} &>/dev/null; then log_message "INFO" "User ${settings.manage_username} exists" "user_deletion.log" exit 0 else log_message "ERROR" "User ${settings.manage_username} does not exist" "user_deletion.log" echo "User does not exist" exit 1 fi - if ("${response.exitStatus}" != "0"): return: type: error message: "User ${settings.manage_username} does not exist." # Check if user is in sftpusers directory - cmd[cp]: user: root commands: |- # Source the logging helper source /home/jelastic/add-sftp-user-addon/log_helper.sh log_message "INFO" "Checking home directory for: ${settings.manage_username}" "user_deletion.log" if test -d /home/sftpusers/${settings.manage_username}; then log_message "INFO" "Home directory found: /home/sftpusers/${settings.manage_username}" "user_deletion.log" exit 0 else log_message "ERROR" "Home directory not found for user: ${settings.manage_username}" "user_deletion.log" echo "User home directory not found" exit 1 fi - if ("${response.exitStatus}" != "0"): return: type: error message: "User ${settings.manage_username} exists but their home directory was not found." # Perform deletion - cmd[cp]: user: root commands: |- # Source the logging helper source /home/jelastic/add-sftp-user-addon/log_helper.sh log_message "INFO" "Starting deletion of user: ${settings.manage_username}" "user_deletion.log" # First unmount any bind mounts if mount | grep -q "/home/sftpusers/${settings.manage_username}/data/ROOT"; then log_message "INFO" "Unmounting bind mount for user: ${settings.manage_username}" "user_deletion.log" umount /home/sftpusers/${settings.manage_username}/data/ROOT fi # Remove from fstab if grep -q "/home/sftpusers/${settings.manage_username}/data/ROOT" /etc/fstab; then log_message "INFO" "Removing bind mount from fstab for user: ${settings.manage_username}" "user_deletion.log" sed -i "\|/home/sftpusers/${settings.manage_username}/data/ROOT|d" /etc/fstab fi # Delete user account if userdel ${settings.manage_username}; then log_message "SUCCESS" "User account deleted: ${settings.manage_username}" "user_deletion.log" else log_message "ERROR" "Failed to delete user account: ${settings.manage_username}" "user_deletion.log" exit 1 fi # Remove home directory if rm -rf /home/sftpusers/${settings.manage_username}; then log_message "SUCCESS" "Home directory removed: /home/sftpusers/${settings.manage_username}" "user_deletion.log" else log_message "WARNING" "Failed to remove home directory for: ${settings.manage_username}" "user_deletion.log" fi log_message "SUCCESS" "======== USER DELETION COMPLETED ========" "user_deletion.log" exit 0 - if ("${response.exitStatus}" != "0"): return: deleteUserError - return: deleteUserSuccess list_users: - cmd[cp]: user: root commands: |- # Create log file for this run LOG_FILE="/home/jelastic/add-sftp-user-addon/logs/list_users.log" touch "$LOG_FILE" # Source the logging helper source /home/jelastic/add-sftp-user-addon/log_helper.sh # Log start of process log_message "INFO" "======== LISTING SFTP USERS ========" "list_users.log" log_message "INFO" "Retrieving list of SFTP users" "list_users.log" # List users without logging to stdout - only return the clean list USERS_LIST=$(ls -ld /home/sftpusers/* 2>/dev/null | grep -v "total" | awk '{printf "Username: %s - Created: %s %s %s\n", substr($9, 17), $6, $7, $8}') # Check if any users were found if [ -z "$USERS_LIST" ]; then log_message "WARNING" "No SFTP users found" "list_users.log" log_message "INFO" "======== USER LISTING COMPLETED ========" "list_users.log" echo "" else log_message "SUCCESS" "Retrieved list of SFTP users" "list_users.log" log_message "DEBUG" "Found users: $(echo "$USERS_LIST" | wc -l)" "list_users.log" log_message "INFO" "======== USER LISTING COMPLETED ========" "list_users.log" echo "$USERS_LIST" fi - if ("${response.exitStatus}" != "0" || "${response.out}" == ""): return: type: warning message: "No SFTP users found. Use the Add SFTP/SSH User button to create one." - return: listUsers responses: installSuccess: type: success message: "Add SFTP User addon installed successfully for Jelastic Virtuozzo LLSMP" sftpError: type: error message: "Failed to add SFTP user. Please check the server logs for more details." sftpSuccess: type: success message: "Connection Details\n\nSFTP Host: ${globals.sftpHost}\n\nPort: ${globals.sftpPort}\n\nLogin Credentials\n\nUsername: ${globals.username}\n\nPassword: ${globals.password}" passwordChangeError: type: error message: "Failed to change password for ${settings.manage_username}. Check logs for details." passwordChangeSuccess: type: success message: "Password changed successfully for ${settings.manage_username}.\n\n New password: ${globals.password}" deleteUserError: type: error message: "Failed to delete user ${settings.manage_username}. Check logs for details." deleteUserSuccess: type: success message: "User ${settings.manage_username} deleted successfully." noUsersFound: type: error message: "No SFTP users have been created yet." listUsers: type: info message: "${response.out}" buttons: - settings: sfpform action: add_sftp_user caption: Add SFTP/SSH User confirmText: "Are you sure you want to add this SFTP user?" submitButtonText: Add User - settings: manageUserForm action: change_password caption: Change Password confirmText: "Are you sure you want to change the password for this user?" submitButtonText: Change Password - settings: deleteUserForm action: delete_user caption: Delete User confirmText: "Are you sure you want to delete this user? This action cannot be undone." submitButtonText: Delete User onUninstall: - cmd[cp]: user: root commands: - rm -rf /home/jelastic/add-sftp-user-addon/