4 Комити 784ed39930 ... e8c509c720

Аутор SHA1 Порука Датум
  JieXu e8c509c720 Update for Red Hat base Linux (#3589) пре 1 недеља
  Roman Gogolev 83a1c721c7 Fix int64 for 32-bit arch (#3591) пре 1 недеља
  Anton Petrov 7ccc0877a1 Add "Last Online" printing for Telegram bot (#3593) пре 1 недеља
  Evgeny Popov ad659e48cf Update x-ui.sh (#3595) пре 1 недеља

+ 47 - 43
install.sh

@@ -15,7 +15,7 @@ cur_dir=$(pwd)
 if [[ -f /etc/os-release ]]; then
     source /etc/os-release
     release=$ID
-elif [[ -f /usr/lib/os-release ]]; then
+    elif [[ -f /usr/lib/os-release ]]; then
     source /usr/lib/os-release
     release=$ID
 else
@@ -26,14 +26,14 @@ echo "The OS release is: $release"
 
 arch() {
     case "$(uname -m)" in
-    x86_64 | x64 | amd64) echo 'amd64' ;;
-    i*86 | x86) echo '386' ;;
-    armv8* | armv8 | arm64 | aarch64) echo 'arm64' ;;
-    armv7* | armv7 | arm) echo 'armv7' ;;
-    armv6* | armv6) echo 'armv6' ;;
-    armv5* | armv5) echo 'armv5' ;;
-    s390x) echo 's390x' ;;
-    *) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;;
+        x86_64 | x64 | amd64) echo 'amd64' ;;
+        i*86 | x86) echo '386' ;;
+        armv8* | armv8 | arm64 | aarch64) echo 'arm64' ;;
+        armv7* | armv7 | arm) echo 'armv7' ;;
+        armv6* | armv6) echo 'armv6' ;;
+        armv5* | armv5) echo 'armv5' ;;
+        s390x) echo 's390x' ;;
+        *) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;;
     esac
 }
 
@@ -41,26 +41,30 @@ echo "Arch: $(arch)"
 
 install_base() {
     case "${release}" in
-    ubuntu | debian | armbian)
-        apt-get update && apt-get install -y -q wget curl tar tzdata
+        ubuntu | debian | armbian)
+            apt-get update && apt-get install -y -q wget curl tar tzdata
         ;;
-    centos | rhel | almalinux | rocky | ol)
-        yum -y update && yum install -y -q wget curl tar tzdata
+        fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
+            dnf -y update && dnf install -y -q wget curl tar tzdata
         ;;
-    fedora | amzn | virtuozzo)
-        dnf -y update && dnf install -y -q wget curl tar tzdata
+        centos)
+            if [[ "${VERSION_ID}" =~ ^7 ]]; then
+                yum -y update && yum install -y wget curl tar tzdata
+            else
+                dnf -y update && dnf install -y -q wget curl tar tzdata
+            fi
         ;;
-    arch | manjaro | parch)
-        pacman -Syu && pacman -Syu --noconfirm wget curl tar tzdata
+        arch | manjaro | parch)
+            pacman -Syu && pacman -Syu --noconfirm wget curl tar tzdata
         ;;
-    opensuse-tumbleweed | opensuse-leap)
-        zypper refresh && zypper -q install -y wget curl tar timezone
+        opensuse-tumbleweed | opensuse-leap)
+            zypper refresh && zypper -q install -y wget curl tar timezone
         ;;
-    alpine)
-        apk update && apk add wget curl tar tzdata
+        alpine)
+            apk update && apk add wget curl tar tzdata
         ;;
-    *)
-        apt-get update && apt-get install -y -q wget curl tar tzdata
+        *)
+            apt-get update && apt-get install -y -q wget curl tar tzdata
         ;;
     esac
 }
@@ -77,11 +81,11 @@ config_after_install() {
     local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}')
     local URL_lists=(
         "https://api4.ipify.org"
-		"https://ipv4.icanhazip.com"
-		"https://v4.api.ipinfo.io/ip"
-		"https://ipv4.myexternalip.com/raw"
-		"https://4.ident.me"
-		"https://check-host.net/ip"
+        "https://ipv4.icanhazip.com"
+        "https://v4.api.ipinfo.io/ip"
+        "https://ipv4.myexternalip.com/raw"
+        "https://4.ident.me"
+        "https://check-host.net/ip"
     )
     local server_ip=""
     for ip_address in "${URL_lists[@]}"; do
@@ -90,13 +94,13 @@ config_after_install() {
             break
         fi
     done
-
+    
     if [[ ${#existing_webBasePath} -lt 4 ]]; then
         if [[ "$existing_hasDefaultCredential" == "true" ]]; then
             local config_webBasePath=$(gen_random_string 18)
             local config_username=$(gen_random_string 10)
             local config_password=$(gen_random_string 10)
-
+            
             read -rp "Would you like to customize the Panel Port settings? (If not, a random port will be applied) [y/n]: " config_confirm
             if [[ "${config_confirm}" == "y" || "${config_confirm}" == "Y" ]]; then
                 read -rp "Please set up the panel port: " config_port
@@ -105,7 +109,7 @@ config_after_install() {
                 local config_port=$(shuf -i 1024-62000 -n 1)
                 echo -e "${yellow}Generated random port: ${config_port}${plain}"
             fi
-
+            
             /usr/local/x-ui/x-ui setting -username "${config_username}" -password "${config_password}" -port "${config_port}" -webBasePath "${config_webBasePath}"
             echo -e "This is a fresh installation, generating random login info for security concerns:"
             echo -e "###############################################"
@@ -126,7 +130,7 @@ config_after_install() {
         if [[ "$existing_hasDefaultCredential" == "true" ]]; then
             local config_username=$(gen_random_string 10)
             local config_password=$(gen_random_string 10)
-
+            
             echo -e "${yellow}Default credentials detected. Security update required...${plain}"
             /usr/local/x-ui/x-ui setting -username "${config_username}" -password "${config_password}"
             echo -e "Generated new random login credentials:"
@@ -138,13 +142,13 @@ config_after_install() {
             echo -e "${green}Username, Password, and WebBasePath are properly set. Exiting...${plain}"
         fi
     fi
-
+    
     /usr/local/x-ui/x-ui migrate
 }
 
 install_x-ui() {
     cd /usr/local/
-
+    
     # Download resources
     if [ $# == 0 ]; then
         tag_version=$(curl -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
@@ -166,12 +170,12 @@ install_x-ui() {
         tag_version=$1
         tag_version_numeric=${tag_version#v}
         min_version="2.3.5"
-
+        
         if [[ "$(printf '%s\n' "$min_version" "$tag_version_numeric" | sort -V | head -n1)" != "$min_version" ]]; then
             echo -e "${red}Please use a newer version (at least v2.3.5). Exiting installation.${plain}"
             exit 1
         fi
-
+        
         url="https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz"
         echo -e "Beginning to install x-ui $1"
         wget --inet4-only -N -O /usr/local/x-ui-linux-$(arch).tar.gz ${url}
@@ -185,7 +189,7 @@ install_x-ui() {
         echo -e "${red}Failed to download x-ui.sh${plain}"
         exit 1
     fi
-
+    
     # Stop x-ui service and remove old resources
     if [[ -e /usr/local/x-ui/ ]]; then
         if [[ $release == "alpine" ]]; then
@@ -195,7 +199,7 @@ install_x-ui() {
         fi
         rm /usr/local/x-ui/ -rf
     fi
-
+    
     # Extract resources and set permissions
     tar zxvf x-ui-linux-$(arch).tar.gz
     rm x-ui-linux-$(arch).tar.gz -f
@@ -203,19 +207,19 @@ install_x-ui() {
     cd x-ui
     chmod +x x-ui
     chmod +x x-ui.sh
-
+    
     # Check the system's architecture and rename the file accordingly
     if [[ $(arch) == "armv5" || $(arch) == "armv6" || $(arch) == "armv7" ]]; then
         mv bin/xray-linux-$(arch) bin/xray-linux-arm
         chmod +x bin/xray-linux-arm
     fi
     chmod +x x-ui bin/xray-linux-$(arch)
-
+    
     # Update x-ui cli and se set permission
     mv -f /usr/bin/x-ui-temp /usr/bin/x-ui
     chmod +x /usr/bin/x-ui
     config_after_install
-
+    
     if [[ $release == "alpine" ]]; then
         wget --inet4-only -O /etc/init.d/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc
         if [[ $? -ne 0 ]]; then
@@ -231,7 +235,7 @@ install_x-ui() {
         systemctl enable x-ui
         systemctl start x-ui
     fi
-
+    
     echo -e "${green}x-ui ${tag_version}${plain} installation finished, it is running now..."
     echo -e ""
     echo -e "┌───────────────────────────────────────────────────────┐
@@ -251,7 +255,7 @@ install_x-ui() {
 │  ${blue}x-ui legacy${plain}       - Legacy version                   │
 │  ${blue}x-ui install${plain}      - Install                          │
 │  ${blue}x-ui uninstall${plain}    - Uninstall                        │
-└───────────────────────────────────────────────────────┘"
+    └───────────────────────────────────────────────────────┘"
 }
 
 echo -e "${green}Running...${plain}"

+ 190 - 186
update.sh

@@ -9,233 +9,237 @@ plain='\033[0m'
 # Don't edit this config
 b_source="${BASH_SOURCE[0]}"
 while [ -h "$b_source" ]; do
-	b_dir="$(cd -P "$(dirname "$b_source")" >/dev/null 2>&1 && pwd || pwd -P)"
-	b_source="$(readlink "$b_source")"
-	[[ $b_source != /* ]] && b_source="$b_dir/$b_source"
+    b_dir="$(cd -P "$(dirname "$b_source")" >/dev/null 2>&1 && pwd || pwd -P)"
+    b_source="$(readlink "$b_source")"
+    [[ $b_source != /* ]] && b_source="$b_dir/$b_source"
 done
 cur_dir="$(cd -P "$(dirname "$b_source")" >/dev/null 2>&1 && pwd || pwd -P)"
 script_name=$(basename "$0")
 
 # Check command exist function
 _command_exists() {
-	type "$1" &>/dev/null
+    type "$1" &>/dev/null
 }
 
 # Fail, log and exit script function
 _fail() {
-	local msg=${1}
-	echo -e "${red}${msg}${plain}"
-	exit 2
+    local msg=${1}
+    echo -e "${red}${msg}${plain}"
+    exit 2
 }
 
 # check root
 [[ $EUID -ne 0 ]] && _fail "FATAL ERROR: Please run this script with root privilege."
 
 if _command_exists wget; then
-	wget_bin=$(which wget)
+    wget_bin=$(which wget)
 else
-	_fail "ERROR: Command 'wget' not found."
+    _fail "ERROR: Command 'wget' not found."
 fi
 
 if _command_exists curl; then
-	curl_bin=$(which curl)
+    curl_bin=$(which curl)
 else
-	_fail "ERROR: Command 'curl' not found."
+    _fail "ERROR: Command 'curl' not found."
 fi
 
 # Check OS and set release variable
 if [[ -f /etc/os-release ]]; then
-	source /etc/os-release
-	release=$ID
-elif [[ -f /usr/lib/os-release ]]; then
-	source /usr/lib/os-release
-	release=$ID
+    source /etc/os-release
+    release=$ID
+    elif [[ -f /usr/lib/os-release ]]; then
+    source /usr/lib/os-release
+    release=$ID
 else
-	_fail "Failed to check the system OS, please contact the author!"
+    _fail "Failed to check the system OS, please contact the author!"
 fi
 echo "The OS release is: $release"
 
 arch() {
-	case "$(uname -m)" in
-	x86_64 | x64 | amd64) echo 'amd64' ;;
-	i*86 | x86) echo '386' ;;
-	armv8* | armv8 | arm64 | aarch64) echo 'arm64' ;;
-	armv7* | armv7 | arm) echo 'armv7' ;;
-	armv6* | armv6) echo 'armv6' ;;
-	armv5* | armv5) echo 'armv5' ;;
-	s390x) echo 's390x' ;;
-	*) echo -e "${red}Unsupported CPU architecture!${plain}" && rm -f "${cur_dir}/${script_name}" >/dev/null 2>&1 && exit 2;;
-	esac
+    case "$(uname -m)" in
+        x86_64 | x64 | amd64) echo 'amd64' ;;
+        i*86 | x86) echo '386' ;;
+        armv8* | armv8 | arm64 | aarch64) echo 'arm64' ;;
+        armv7* | armv7 | arm) echo 'armv7' ;;
+        armv6* | armv6) echo 'armv6' ;;
+        armv5* | armv5) echo 'armv5' ;;
+        s390x) echo 's390x' ;;
+        *) echo -e "${red}Unsupported CPU architecture!${plain}" && rm -f "${cur_dir}/${script_name}" >/dev/null 2>&1 && exit 2;;
+    esac
 }
 
 echo "Arch: $(arch)"
 
 install_base() {
-	echo -e "${green}Updating and install dependency packages...${plain}"
-	case "${release}" in
-	ubuntu | debian | armbian)
-		apt-get update >/dev/null 2>&1 && apt-get install -y -q wget curl tar tzdata >/dev/null 2>&1
-		;;
-	centos | rhel | almalinux | rocky | ol)
-		yum -y update >/dev/null 2>&1 && yum install -y -q wget curl tar tzdata >/dev/null 2>&1
-		;;
-	fedora | amzn | virtuozzo)
-		dnf -y update >/dev/null 2>&1 && dnf install -y -q wget curl tar tzdata >/dev/null 2>&1
-		;;
-	arch | manjaro | parch)
-		pacman -Syu >/dev/null 2>&1 && pacman -Syu --noconfirm wget curl tar tzdata >/dev/null 2>&1
-		;;
-	opensuse-tumbleweed | opensuse-leap)
-		zypper refresh >/dev/null 2>&1 && zypper -q install -y wget curl tar timezone >/dev/null 2>&1
-		;;
-	alpine)
-		apk update >/dev/null 2>&1 && apk add wget curl tar tzdata >/dev/null 2>&1
-		;;
-	*)
-		apt-get update >/dev/null 2>&1 && apt install -y -q wget curl tar tzdata >/dev/null 2>&1
-		;;
-	esac
+    echo -e "${green}Updating and install dependency packages...${plain}"
+    case "${release}" in
+        ubuntu | debian | armbian)
+            apt-get update >/dev/null 2>&1 && apt-get install -y -q wget curl tar tzdata >/dev/null 2>&1
+        ;;
+        fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
+            dnf -y update >/dev/null 2>&1 && dnf install -y -q wget curl tar tzdata >/dev/null 2>&1
+        ;;
+        centos)
+            if [[ "${VERSION_ID}" =~ ^7 ]]; then
+                yum -y update >/dev/null 2>&1 && yum install -y -q wget curl tar tzdata >/dev/null 2>&1
+            else
+                dnf -y update >/dev/null 2>&1 && dnf install -y -q wget curl tar tzdata >/dev/null 2>&1
+            fi
+        ;;
+        arch | manjaro | parch)
+            pacman -Syu >/dev/null 2>&1 && pacman -Syu --noconfirm wget curl tar tzdata >/dev/null 2>&1
+        ;;
+        opensuse-tumbleweed | opensuse-leap)
+            zypper refresh >/dev/null 2>&1 && zypper -q install -y wget curl tar timezone >/dev/null 2>&1
+        ;;
+        alpine)
+            apk update >/dev/null 2>&1 && apk add wget curl tar tzdata >/dev/null 2>&1
+        ;;
+        *)
+            apt-get update >/dev/null 2>&1 && apt install -y -q wget curl tar tzdata >/dev/null 2>&1
+        ;;
+    esac
 }
 
 config_after_update() {
-	echo -e "${yellow}x-ui settings:${plain}"
-	/usr/local/x-ui/x-ui setting -show true
-	/usr/local/x-ui/x-ui migrate
+    echo -e "${yellow}x-ui settings:${plain}"
+    /usr/local/x-ui/x-ui setting -show true
+    /usr/local/x-ui/x-ui migrate
 }
 
 update_x-ui() {
-	cd /usr/local/
-
-	if [ -f "/usr/local/x-ui/x-ui" ]; then
-		current_xui_version=$(/usr/local/x-ui/x-ui -v)
-		echo -e "${green}Current x-ui version: ${current_xui_version}${plain}"
-	else
-		_fail "ERROR: Current x-ui version: unknown"
-	fi
-
-	echo -e "${green}Downloading new x-ui version...${plain}"
-
-	tag_version=$(${curl_bin} -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" 2>/dev/null | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
-	if [[ ! -n "$tag_version" ]]; then
-		echo -e "${yellow}Trying to fetch version with IPv4...${plain}"
-		tag_version=$(${curl_bin} -4 -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
-		if [[ ! -n "$tag_version" ]]; then
-			_fail "ERROR: Failed to fetch x-ui version, it may be due to GitHub API restrictions, please try it later"
-		fi
-	fi
-	echo -e "Got x-ui latest version: ${tag_version}, beginning the installation..."
-	${wget_bin} -N -O /usr/local/x-ui-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2>/dev/null
-	if [[ $? -ne 0 ]]; then
-		echo -e "${yellow}Trying to fetch version with IPv4...${plain}"
-		${wget_bin} --inet4-only -N -O /usr/local/x-ui-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2>/dev/null
-		if [[ $? -ne 0 ]]; then
-			_fail "ERROR: Failed to download x-ui, please be sure that your server can access GitHub"
-		fi
-	fi
-
-	if [[ -e /usr/local/x-ui/ ]]; then
-		echo -e "${green}Stopping x-ui...${plain}"
-		if [[ $release == "alpine" ]]; then
-			if [ -f "/etc/init.d/x-ui" ]; then
-				rc-service x-ui stop >/dev/null 2>&1
-				rc-update del x-ui >/dev/null 2>&1
-				echo -e "${green}Removing old service unit version...${plain}"
-				rm -f /etc/init.d/x-ui >/dev/null 2>&1
-			else
-				rm x-ui-linux-$(arch).tar.gz -f >/dev/null 2>&1
-				_fail "ERROR: x-ui service unit not installed."
-			fi
-		else
-			if [ -f "/etc/systemd/system/x-ui.service" ]; then
-				systemctl stop x-ui >/dev/null 2>&1
-				systemctl disable x-ui >/dev/null 2>&1
-				echo -e "${green}Removing old systemd unit version...${plain}"
-				rm /etc/systemd/system/x-ui.service -f >/dev/null 2>&1
-				systemctl daemon-reload >/dev/null 2>&1
-			else
-				rm x-ui-linux-$(arch).tar.gz -f >/dev/null 2>&1
-				_fail "ERROR: x-ui systemd unit not installed."
-			fi
-		fi
-		echo -e "${green}Removing old x-ui version...${plain}"
-		rm /usr/bin/x-ui -f >/dev/null 2>&1
-		rm /usr/local/x-ui/x-ui.service -f >/dev/null 2>&1
-		rm /usr/local/x-ui/x-ui -f >/dev/null 2>&1
-		rm /usr/local/x-ui/x-ui.sh -f >/dev/null 2>&1
-		echo -e "${green}Removing old xray version...${plain}"
-		rm /usr/local/x-ui/bin/xray-linux-amd64 -f >/dev/null 2>&1
-		echo -e "${green}Removing old README and LICENSE file...${plain}"
-		rm /usr/local/x-ui/bin/README.md -f >/dev/null 2>&1
-		rm /usr/local/x-ui/bin/LICENSE -f >/dev/null 2>&1
-	else
-		rm x-ui-linux-$(arch).tar.gz -f >/dev/null 2>&1
-		_fail "ERROR: x-ui not installed."
-	fi
-
-	echo -e "${green}Installing new x-ui version...${plain}"
-	tar zxvf x-ui-linux-$(arch).tar.gz >/dev/null 2>&1
-	rm x-ui-linux-$(arch).tar.gz -f >/dev/null 2>&1
-	cd x-ui >/dev/null 2>&1
-	chmod +x x-ui >/dev/null 2>&1
-
-	# Check the system's architecture and rename the file accordingly
-	if [[ $(arch) == "armv5" || $(arch) == "armv6" || $(arch) == "armv7" ]]; then
-		mv bin/xray-linux-$(arch) bin/xray-linux-arm >/dev/null 2>&1
-		chmod +x bin/xray-linux-arm >/dev/null 2>&1
-	fi
-
-	chmod +x x-ui bin/xray-linux-$(arch) >/dev/null 2>&1
-
-	echo -e "${green}Downloading and installing x-ui.sh script...${plain}"
-	${wget_bin} -O /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh >/dev/null 2>&1
-	if [[ $? -ne 0 ]]; then
-		echo -e "${yellow}Trying to fetch x-ui with IPv4...${plain}"
-		${wget_bin} --inet4-only -O /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh >/dev/null 2>&1
-		if [[ $? -ne 0 ]]; then
-			_fail "ERROR: Failed to download x-ui.sh script, please be sure that your server can access GitHub"
-		fi
-	fi
-
-	chmod +x /usr/local/x-ui/x-ui.sh >/dev/null 2>&1
-	chmod +x /usr/bin/x-ui >/dev/null 2>&1
-
-	echo -e "${green}Changing owner...${plain}"
-	chown -R root:root /usr/local/x-ui >/dev/null 2>&1
-
-	if [ -f "/usr/local/x-ui/bin/config.json" ]; then
-		echo -e "${green}Changing on config file permissions...${plain}"
-		chmod 640 /usr/local/x-ui/bin/config.json >/dev/null 2>&1
-	fi
-
-	if [[ $release == "alpine" ]]; then
-		echo -e "${green}Downloading and installing startup unit x-ui.rc...${plain}"
-		${wget_bin} -O /etc/init.d/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc >/dev/null 2>&1
-		if [[ $? -ne 0 ]]; then
-			${wget_bin} --inet4-only -O /etc/init.d/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc >/dev/null 2>&1
-			if [[ $? -ne 0 ]]; then
-				_fail "ERROR: Failed to download startup unit x-ui.rc, please be sure that your server can access GitHub"
-			fi
-		fi
-		chmod +x /etc/init.d/x-ui >/dev/null 2>&1
-		chown root:root /etc/init.d/x-ui >/dev/null 2>&1
-		rc-update add x-ui >/dev/null 2>&1
-		rc-service x-ui start >/dev/null 2>&1
-	else
-		echo -e "${green}Installing systemd unit...${plain}"
-		cp -f x-ui.service /etc/systemd/system/ >/dev/null 2>&1
-		chown root:root /etc/systemd/system/x-ui.service >/dev/null 2>&1
-		systemctl daemon-reload >/dev/null 2>&1
-		systemctl enable x-ui >/dev/null 2>&1
-		systemctl start x-ui >/dev/null 2>&1
-	fi
-
-	config_after_update
-
-	echo -e "${green}x-ui ${tag_version}${plain} updating finished, it is running now..."
-	echo -e ""
-	echo -e "┌───────────────────────────────────────────────────────┐
+    cd /usr/local/
+    
+    if [ -f "/usr/local/x-ui/x-ui" ]; then
+        current_xui_version=$(/usr/local/x-ui/x-ui -v)
+        echo -e "${green}Current x-ui version: ${current_xui_version}${plain}"
+    else
+        _fail "ERROR: Current x-ui version: unknown"
+    fi
+    
+    echo -e "${green}Downloading new x-ui version...${plain}"
+    
+    tag_version=$(${curl_bin} -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" 2>/dev/null | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
+    if [[ ! -n "$tag_version" ]]; then
+        echo -e "${yellow}Trying to fetch version with IPv4...${plain}"
+        tag_version=$(${curl_bin} -4 -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
+        if [[ ! -n "$tag_version" ]]; then
+            _fail "ERROR: Failed to fetch x-ui version, it may be due to GitHub API restrictions, please try it later"
+        fi
+    fi
+    echo -e "Got x-ui latest version: ${tag_version}, beginning the installation..."
+    ${wget_bin} -N -O /usr/local/x-ui-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2>/dev/null
+    if [[ $? -ne 0 ]]; then
+        echo -e "${yellow}Trying to fetch version with IPv4...${plain}"
+        ${wget_bin} --inet4-only -N -O /usr/local/x-ui-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2>/dev/null
+        if [[ $? -ne 0 ]]; then
+            _fail "ERROR: Failed to download x-ui, please be sure that your server can access GitHub"
+        fi
+    fi
+    
+    if [[ -e /usr/local/x-ui/ ]]; then
+        echo -e "${green}Stopping x-ui...${plain}"
+        if [[ $release == "alpine" ]]; then
+            if [ -f "/etc/init.d/x-ui" ]; then
+                rc-service x-ui stop >/dev/null 2>&1
+                rc-update del x-ui >/dev/null 2>&1
+                echo -e "${green}Removing old service unit version...${plain}"
+                rm -f /etc/init.d/x-ui >/dev/null 2>&1
+            else
+                rm x-ui-linux-$(arch).tar.gz -f >/dev/null 2>&1
+                _fail "ERROR: x-ui service unit not installed."
+            fi
+        else
+            if [ -f "/etc/systemd/system/x-ui.service" ]; then
+                systemctl stop x-ui >/dev/null 2>&1
+                systemctl disable x-ui >/dev/null 2>&1
+                echo -e "${green}Removing old systemd unit version...${plain}"
+                rm /etc/systemd/system/x-ui.service -f >/dev/null 2>&1
+                systemctl daemon-reload >/dev/null 2>&1
+            else
+                rm x-ui-linux-$(arch).tar.gz -f >/dev/null 2>&1
+                _fail "ERROR: x-ui systemd unit not installed."
+            fi
+        fi
+        echo -e "${green}Removing old x-ui version...${plain}"
+        rm /usr/bin/x-ui -f >/dev/null 2>&1
+        rm /usr/local/x-ui/x-ui.service -f >/dev/null 2>&1
+        rm /usr/local/x-ui/x-ui -f >/dev/null 2>&1
+        rm /usr/local/x-ui/x-ui.sh -f >/dev/null 2>&1
+        echo -e "${green}Removing old xray version...${plain}"
+        rm /usr/local/x-ui/bin/xray-linux-amd64 -f >/dev/null 2>&1
+        echo -e "${green}Removing old README and LICENSE file...${plain}"
+        rm /usr/local/x-ui/bin/README.md -f >/dev/null 2>&1
+        rm /usr/local/x-ui/bin/LICENSE -f >/dev/null 2>&1
+    else
+        rm x-ui-linux-$(arch).tar.gz -f >/dev/null 2>&1
+        _fail "ERROR: x-ui not installed."
+    fi
+    
+    echo -e "${green}Installing new x-ui version...${plain}"
+    tar zxvf x-ui-linux-$(arch).tar.gz >/dev/null 2>&1
+    rm x-ui-linux-$(arch).tar.gz -f >/dev/null 2>&1
+    cd x-ui >/dev/null 2>&1
+    chmod +x x-ui >/dev/null 2>&1
+    
+    # Check the system's architecture and rename the file accordingly
+    if [[ $(arch) == "armv5" || $(arch) == "armv6" || $(arch) == "armv7" ]]; then
+        mv bin/xray-linux-$(arch) bin/xray-linux-arm >/dev/null 2>&1
+        chmod +x bin/xray-linux-arm >/dev/null 2>&1
+    fi
+    
+    chmod +x x-ui bin/xray-linux-$(arch) >/dev/null 2>&1
+    
+    echo -e "${green}Downloading and installing x-ui.sh script...${plain}"
+    ${wget_bin} -O /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh >/dev/null 2>&1
+    if [[ $? -ne 0 ]]; then
+        echo -e "${yellow}Trying to fetch x-ui with IPv4...${plain}"
+        ${wget_bin} --inet4-only -O /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh >/dev/null 2>&1
+        if [[ $? -ne 0 ]]; then
+            _fail "ERROR: Failed to download x-ui.sh script, please be sure that your server can access GitHub"
+        fi
+    fi
+    
+    chmod +x /usr/local/x-ui/x-ui.sh >/dev/null 2>&1
+    chmod +x /usr/bin/x-ui >/dev/null 2>&1
+    
+    echo -e "${green}Changing owner...${plain}"
+    chown -R root:root /usr/local/x-ui >/dev/null 2>&1
+    
+    if [ -f "/usr/local/x-ui/bin/config.json" ]; then
+        echo -e "${green}Changing on config file permissions...${plain}"
+        chmod 640 /usr/local/x-ui/bin/config.json >/dev/null 2>&1
+    fi
+    
+    if [[ $release == "alpine" ]]; then
+        echo -e "${green}Downloading and installing startup unit x-ui.rc...${plain}"
+        ${wget_bin} -O /etc/init.d/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc >/dev/null 2>&1
+        if [[ $? -ne 0 ]]; then
+            ${wget_bin} --inet4-only -O /etc/init.d/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc >/dev/null 2>&1
+            if [[ $? -ne 0 ]]; then
+                _fail "ERROR: Failed to download startup unit x-ui.rc, please be sure that your server can access GitHub"
+            fi
+        fi
+        chmod +x /etc/init.d/x-ui >/dev/null 2>&1
+        chown root:root /etc/init.d/x-ui >/dev/null 2>&1
+        rc-update add x-ui >/dev/null 2>&1
+        rc-service x-ui start >/dev/null 2>&1
+    else
+        echo -e "${green}Installing systemd unit...${plain}"
+        cp -f x-ui.service /etc/systemd/system/ >/dev/null 2>&1
+        chown root:root /etc/systemd/system/x-ui.service >/dev/null 2>&1
+        systemctl daemon-reload >/dev/null 2>&1
+        systemctl enable x-ui >/dev/null 2>&1
+        systemctl start x-ui >/dev/null 2>&1
+    fi
+    
+    config_after_update
+    
+    echo -e "${green}x-ui ${tag_version}${plain} updating finished, it is running now..."
+    echo -e ""
+    echo -e "┌───────────────────────────────────────────────────────┐
 │  ${blue}x-ui control menu usages (subcommands):${plain}              │
-│                                                       │	
+│                                                       │
 │  ${blue}x-ui${plain}              - Admin Management Script          │
 │  ${blue}x-ui start${plain}        - Start                            │
 │  ${blue}x-ui stop${plain}         - Stop                             │
@@ -250,7 +254,7 @@ update_x-ui() {
 │  ${blue}x-ui legacy${plain}       - Legacy version                   │
 │  ${blue}x-ui install${plain}      - Install                          │
 │  ${blue}x-ui uninstall${plain}    - Uninstall                        │
-└───────────────────────────────────────────────────────┘"
+    └───────────────────────────────────────────────────────┘"
 }
 
 echo -e "${green}Running...${plain}"

+ 10 - 5
web/service/tgbot.go

@@ -210,7 +210,7 @@ func (t *Tgbot) Start(i18nFS embed.FS) error {
 	// Parse admin IDs from comma-separated string
 	if tgBotID != "" {
 		for _, adminID := range strings.Split(tgBotID, ",") {
-			id, err := strconv.Atoi(adminID)
+			id, err := strconv.ParseInt(adminID, 10, 64)
 			if err != nil {
 				logger.Warning("Failed to parse admin ID from Telegram bot chat ID:", err)
 				return err
@@ -905,8 +905,8 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
 				t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
 				t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
 			case "add_client_limit_traffic_c":
-				limitTraffic, _ := strconv.Atoi(dataArray[1])
-				client_TotalGB = int64(limitTraffic) * 1024 * 1024 * 1024
+				limitTraffic, _ := strconv.ParseInt(dataArray[1], 10, 64)
+				client_TotalGB = limitTraffic * 1024 * 1024 * 1024
 				messageId := callbackQuery.Message.GetMessageID()
 				inbound, err := t.inboundService.GetInbound(receiver_inbound_ID)
 				if err != nil {
@@ -1010,7 +1010,7 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
 				t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
 			case "reset_exp_c":
 				if len(dataArray) == 3 {
-					days, err := strconv.Atoi(dataArray[2])
+					days, err := strconv.ParseInt(dataArray[2], 10, 64)
 					if err == nil {
 						var date int64
 						if days > 0 {
@@ -1115,7 +1115,7 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
 				t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
 			case "add_client_reset_exp_c":
 				client_ExpiryTime = 0
-				days, _ := strconv.Atoi(dataArray[1])
+				days, _ := strconv.ParseInt(dataArray[1], 10, 64)
 				var date int64
 				if client_ExpiryTime > 0 {
 					if client_ExpiryTime-time.Now().Unix()*1000 < 0 {
@@ -2952,10 +2952,12 @@ func (t *Tgbot) clientInfoMsg(
 	}
 
 	status := t.I18nBot("tgbot.offline")
+	isOnline := false
 	if p.IsRunning() {
 		for _, online := range p.GetOnlineClients() {
 			if online == traffic.Email {
 				status = t.I18nBot("tgbot.online")
+				isOnline = true
 				break
 			}
 		}
@@ -2968,6 +2970,9 @@ func (t *Tgbot) clientInfoMsg(
 	}
 	if printOnline {
 		output += t.I18nBot("tgbot.messages.online", "Status=="+status)
+		if !isOnline && traffic.LastOnline > 0 {
+			output += t.I18nBot("tgbot.messages.lastOnline", "Time=="+time.UnixMilli(traffic.LastOnline).Format("2006-01-02 15:04:05"))
+		}
 	}
 	if printActive {
 		output += t.I18nBot("tgbot.messages.active", "Enable=="+active)

+ 5 - 4
web/translation/translate.ar_EG.toml

@@ -106,7 +106,7 @@
 "invalidFormData" = "تنسيق البيانات المدخلة مش صحيح."
 "emptyUsername" = "اسم المستخدم مطلوب"
 "emptyPassword" = "الباسورد مطلوب"
-"wrongUsernameOrPassword" = "اسم المستخدم أو كلمة المرور أو كود المصادقة الثنائية غير صحيح."  
+"wrongUsernameOrPassword" = "اسم المستخدم أو كلمة المرور أو كود المصادقة الثنائية غير صحيح."
 "successLogin" = "لقد تم تسجيل الدخول إلى حسابك بنجاح."
 
 [pages.index]
@@ -565,9 +565,9 @@
 
 [pages.settings.security]
 "admin" = "بيانات الأدمن"
-"twoFactor" = "المصادقة الثنائية"  
-"twoFactorEnable" = "تفعيل المصادقة الثنائية"  
-"twoFactorEnableDesc" = "يضيف طبقة إضافية من المصادقة لتعزيز الأمان."  
+"twoFactor" = "المصادقة الثنائية"
+"twoFactorEnable" = "تفعيل المصادقة الثنائية"
+"twoFactorEnableDesc" = "يضيف طبقة إضافية من المصادقة لتعزيز الأمان."
 "twoFactorModalSetTitle" = "تفعيل المصادقة الثنائية"
 "twoFactorModalDeleteTitle" = "تعطيل المصادقة الثنائية"
 "twoFactorModalSteps" = "لإعداد المصادقة الثنائية، قم ببعض الخطوات:"
@@ -663,6 +663,7 @@
 "active" = "💡 مفعل: {{ .Enable }}\r\n"
 "enabled" = "🚨 مفعل: {{ .Enable }}\r\n"
 "online" = "🌐 حالة الاتصال: {{ .Status }}\r\n"
+"lastOnline" = "🔙 آخر متصل: {{ .Time }}\r\n"
 "email" = "📧 الإيميل: {{ .Email }}\r\n"
 "upload" = "🔼 رفع: ↑{{ .Upload }}\r\n"
 "download" = "🔽 تنزيل: ↓{{ .Download }}\r\n"

+ 4 - 3
web/translation/translate.en_US.toml

@@ -663,6 +663,7 @@
 "active" = "💡 Active: {{ .Enable }}\r\n"
 "enabled" = "🚨 Enabled: {{ .Enable }}\r\n"
 "online" = "🌐 Connection status: {{ .Status }}\r\n"
+"lastOnline" = "🔙 Last online: {{ .Time }}\r\n"
 "email" = "📧 Email: {{ .Email }}\r\n"
 "upload" = "🔼 Upload: ↑{{ .Upload }}\r\n"
 "download" = "🔽 Download: ↓{{ .Download }}\r\n"
@@ -688,9 +689,9 @@
 "inbound_client_data_id" = "🔄 Inbound: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Traffic: {{ .ClientTraffic }}\n📅 Expire Date: {{ .ClientExp }}\n🌐 IP Limit: {{ .IpLimit }}\n💬 Comment: {{ .ClientComment }}\n\nYou can add the client to inbound now!"
 "inbound_client_data_pass" = "🔄 Inbound: {{ .InboundRemark }}\n\n🔑 Password: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Traffic: {{ .ClientTraffic }}\n📅 Expire Date: {{ .ClientExp }}\n🌐 IP Limit: {{ .IpLimit }}\n💬 Comment: {{ .ClientComment }}\n\nYou can add the client to inbound now!"
 "cancel" = "❌ Process Canceled! \n\nYou can /start again anytime. 🔄"
-"error_add_client"  = "⚠️ Error:\n\n {{ .error }}"
-"using_default_value"  = "Okay, I'll stick with the default value. 😊"
-"incorrect_input" ="Your input is not valid.\nThe phrases should be continuous without spaces.\nCorrect example: aaaaaa\nIncorrect example: aaa aaa 🚫"
+"error_add_client" = "⚠️ Error:\n\n {{ .error }}"
+"using_default_value" = "Okay, I'll stick with the default value. 😊"
+"incorrect_input" = "Your input is not valid.\nThe phrases should be continuous without spaces.\nCorrect example: aaaaaa\nIncorrect example: aaa aaa 🚫"
 "AreYouSure" = "Are you sure? 🤔"
 "SuccessResetTraffic" = "📧 Email: {{ .ClientEmail }}\n🏁 Result: ✅ Success"
 "FailedResetTraffic" = "📧 Email: {{ .ClientEmail }}\n🏁 Result: ❌ Failed \n\n🛠️ Error: [ {{ .ErrorMessage }} ]"

+ 4 - 3
web/translation/translate.es_ES.toml

@@ -663,6 +663,7 @@
 "active" = "💡 Activo: {{ .Enable }}\r\n"
 "enabled" = "🚨 Habilitado: {{ .Enable }}\r\n"
 "online" = "🌐 Estado de conexión: {{ .Status }}\r\n"
+"lastOnline" = "🔙 Última conexión: {{ .Time }}\r\n"
 "email" = "📧 Email: {{ .Email }}\r\n"
 "upload" = "🔼 Subida: ↑{{ .Upload }}\r\n"
 "download" = "🔽 Bajada: ↓{{ .Download }}\r\n"
@@ -688,9 +689,9 @@
 "inbound_client_data_id" = "🔄 Entrada: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Correo: {{ .ClientEmail }}\n📊 Tráfico: {{ .ClientTraffic }}\n📅 Fecha de expiración: {{ .ClientExp }}\n🌐 Límite de IP: {{ .IpLimit }}\n💬 Comentario: {{ .ClientComment }}\n\n¡Ahora puedes agregar al cliente a la entrada!"
 "inbound_client_data_pass" = "🔄 Entrada: {{ .InboundRemark }}\n\n🔑 Contraseña: {{ .ClientPass }}\n📧 Correo: {{ .ClientEmail }}\n📊 Tráfico: {{ .ClientTraffic }}\n📅 Fecha de expiración: {{ .ClientExp }}\n🌐 Límite de IP: {{ .IpLimit }}\n💬 Comentario: {{ .ClientComment }}\n\n¡Ahora puedes agregar al cliente a la entrada!"
 "cancel" = "❌ ¡Proceso cancelado! \n\nPuedes /start de nuevo en cualquier momento. 🔄"
-"error_add_client"  = "⚠️ Error:\n\n {{ .error }}"
-"using_default_value"  = "Está bien, me quedaré con el valor predeterminado. 😊"
-"incorrect_input" ="Tu entrada no es válida.\nLas frases deben ser continuas sin espacios.\nEjemplo correcto: aaaaaa\nEjemplo incorrecto: aaa aaa 🚫"
+"error_add_client" = "⚠️ Error:\n\n {{ .error }}"
+"using_default_value" = "Está bien, me quedaré con el valor predeterminado. 😊"
+"incorrect_input" = "Tu entrada no es válida.\nLas frases deben ser continuas sin espacios.\nEjemplo correcto: aaaaaa\nEjemplo incorrecto: aaa aaa 🚫"
 "AreYouSure" = "¿Estás seguro? 🤔"
 "SuccessResetTraffic" = "📧 Correo: {{ .ClientEmail }}\n🏁 Resultado: ✅ Éxito"
 "FailedResetTraffic" = "📧 Correo: {{ .ClientEmail }}\n🏁 Resultado: ❌ Fallido \n\n🛠️ Error: [ {{ .ErrorMessage }} ]"

+ 8 - 7
web/translation/translate.fa_IR.toml

@@ -106,7 +106,7 @@
 "invalidFormData" = "اطلاعات به‌درستی وارد نشده‌است"
 "emptyUsername" = "لطفا یک نام‌کاربری وارد کنید‌"
 "emptyPassword" = "لطفا یک رمزعبور وارد کنید"
-"wrongUsernameOrPassword" = "نام کاربری، رمز عبور یا کد دو مرحله‌ای نامعتبر است."  
+"wrongUsernameOrPassword" = "نام کاربری، رمز عبور یا کد دو مرحله‌ای نامعتبر است."
 "successLogin" = "شما با موفقیت به حساب کاربری خود وارد شدید."
 
 [pages.index]
@@ -565,9 +565,9 @@
 
 [pages.settings.security]
 "admin" = "اعتبارنامه‌های ادمین"
-"twoFactor" = "احراز هویت دو مرحله‌ای"  
-"twoFactorEnable" = "فعال‌سازی 2FA"  
-"twoFactorEnableDesc" = "یک لایه اضافی امنیتی برای احراز هویت فراهم می‌کند."  
+"twoFactor" = "احراز هویت دو مرحله‌ای"
+"twoFactorEnable" = "فعال‌سازی 2FA"
+"twoFactorEnableDesc" = "یک لایه اضافی امنیتی برای احراز هویت فراهم می‌کند."
 "twoFactorModalSetTitle" = "فعال‌سازی احراز هویت دو مرحله‌ای"
 "twoFactorModalDeleteTitle" = "غیرفعال‌سازی احراز هویت دو مرحله‌ای"
 "twoFactorModalSteps" = "برای راه‌اندازی احراز هویت دو مرحله‌ای، مراحل زیر را انجام دهید:"
@@ -663,6 +663,7 @@
 "active" = "💡 فعال: {{ .Enable }}\r\n"
 "enabled" = "🚨 وضعیت: {{ .Enable }}\r\n"
 "online" = "🌐 وضعیت اتصال: {{ .Status }}\r\n"
+"lastOnline" = "🔙 آخرین فعالیت: {{ .Time }}\r\n"
 "email" = "📧 ایمیل: {{ .Email }}\r\n"
 "upload" = "🔼 آپلود↑: {{ .Upload }}\r\n"
 "download" = "🔽 دانلود↓: {{ .Download }}\r\n"
@@ -688,9 +689,9 @@
 "inbound_client_data_id" = "🔄 ورودی: {{ .InboundRemark }}\n\n🔑 شناسه: {{ .ClientId }}\n📧 ایمیل: {{ .ClientEmail }}\n📊 ترافیک: {{ .ClientTraffic }}\n📅 تاریخ انقضا: {{ .ClientExp }}\n🌐 محدودیت IP: {{ .IpLimit }}\n💬 توضیح: {{ .ClientComment }}\n\nاکنون می‌تونی مشتری را به ورودی اضافه کنی!"
 "inbound_client_data_pass" = "🔄 ورودی: {{ .InboundRemark }}\n\n🔑 رمز عبور: {{ .ClientPass }}\n📧 ایمیل: {{ .ClientEmail }}\n📊 ترافیک: {{ .ClientTraffic }}\n📅 تاریخ انقضا: {{ .ClientExp }}\n🌐 محدودیت IP: {{ .IpLimit }}\n💬 توضیح: {{ .ClientComment }}\n\nاکنون می‌تونی مشتری را به ورودی اضافه کنی!"
 "cancel" = "❌ فرآیند لغو شد! \n\nمی‌توانید هر زمان که خواستید /start را دوباره اجرا کنید. 🔄"
-"error_add_client"  = "⚠️ خطا:\n\n {{ .error }}"
-"using_default_value"  = "باشه، از مقدار پیش‌فرض استفاده می‌کنم. 😊"
-"incorrect_input" ="ورودی شما معتبر نیست.\nعبارت‌ها باید بدون فاصله باشند.\nمثال صحیح: aaaaaa\nمثال نادرست: aaa aaa 🚫"
+"error_add_client" = "⚠️ خطا:\n\n {{ .error }}"
+"using_default_value" = "باشه، از مقدار پیش‌فرض استفاده می‌کنم. 😊"
+"incorrect_input" = "ورودی شما معتبر نیست.\nعبارت‌ها باید بدون فاصله باشند.\nمثال صحیح: aaaaaa\nمثال نادرست: aaa aaa 🚫"
 "AreYouSure" = "مطمئنی؟ 🤔"
 "SuccessResetTraffic" = "📧 ایمیل: {{ .ClientEmail }}\n🏁 نتیجه: ✅ موفقیت‌آمیز"
 "FailedResetTraffic" = "📧 ایمیل: {{ .ClientEmail }}\n🏁 نتیجه: ❌ ناموفق \n\n🛠️ خطا: [ {{ .ErrorMessage }} ]"

+ 6 - 5
web/translation/translate.id_ID.toml

@@ -106,12 +106,12 @@
 "invalidFormData" = "Format data input tidak valid."
 "emptyUsername" = "Nama Pengguna diperlukan"
 "emptyPassword" = "Kata Sandi diperlukan"
-"wrongUsernameOrPassword" = "Username, kata sandi, atau kode dua faktor tidak valid."  
+"wrongUsernameOrPassword" = "Username, kata sandi, atau kode dua faktor tidak valid."
 "successLogin" = "Anda telah berhasil masuk ke akun Anda."
 
 [pages.index]
 "title" = "Ikhtisar"
-"cpu" = "CPU" 
+"cpu" = "CPU"
 "logicalProcessors" = "Prosesor logis"
 "frequency" = "Frekuensi"
 "swap" = "Swap"
@@ -663,6 +663,7 @@
 "active" = "💡 Aktif: {{ .Enable }}\r\n"
 "enabled" = "🚨 Diaktifkan: {{ .Enable }}\r\n"
 "online" = "🌐 Status Koneksi: {{ .Status }}\r\n"
+"lastOnline" = "🔙 Terakhir online: {{ .Time }}\r\n"
 "email" = "📧 Email: {{ .Email }}\r\n"
 "upload" = "🔼 Unggah: ↑{{ .Upload }}\r\n"
 "download" = "🔽 Unduh: ↓{{ .Download }}\r\n"
@@ -688,9 +689,9 @@
 "inbound_client_data_id" = "🔄 Masuk: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Lalu lintas: {{ .ClientTraffic }}\n📅 Tanggal Kedaluwarsa: {{ .ClientExp }}\n🌐 Batas IP: {{ .IpLimit }}\n💬 Komentar: {{ .ClientComment }}\n\nSekarang kamu bisa menambahkan klien ke inbound!"
 "inbound_client_data_pass" = "🔄 Masuk: {{ .InboundRemark }}\n\n🔑 Kata sandi: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Lalu lintas: {{ .ClientTraffic }}\n📅 Tanggal Kedaluwarsa: {{ .ClientExp }}\n🌐 Batas IP: {{ .IpLimit }}\n💬 Komentar: {{ .ClientComment }}\n\nSekarang kamu bisa menambahkan klien ke inbound!"
 "cancel" = "❌ Proses Dibatalkan! \n\nAnda dapat /start lagi kapan saja. 🔄"
-"error_add_client"  = "⚠️ Kesalahan:\n\n {{ .error }}"
-"using_default_value"  = "Oke, saya akan tetap menggunakan nilai default. 😊"
-"incorrect_input" ="Masukan Anda tidak valid.\nFrasa harus berlanjut tanpa spasi.\nContoh benar: aaaaaa\nContoh salah: aaa aaa 🚫"
+"error_add_client" = "⚠️ Kesalahan:\n\n {{ .error }}"
+"using_default_value" = "Oke, saya akan tetap menggunakan nilai default. 😊"
+"incorrect_input" = "Masukan Anda tidak valid.\nFrasa harus berlanjut tanpa spasi.\nContoh benar: aaaaaa\nContoh salah: aaa aaa 🚫"
 "AreYouSure" = "Apakah kamu yakin? 🤔"
 "SuccessResetTraffic" = "📧 Email: {{ .ClientEmail }}\n🏁 Hasil: ✅ Berhasil"
 "FailedResetTraffic" = "📧 Email: {{ .ClientEmail }}\n🏁 Hasil: ❌ Gagal \n\n🛠️ Kesalahan: [ {{ .ErrorMessage }} ]"

+ 8 - 7
web/translation/translate.ja_JP.toml

@@ -106,7 +106,7 @@
 "invalidFormData" = "データ形式エラー"
 "emptyUsername" = "ユーザー名を入力してください"
 "emptyPassword" = "パスワードを入力してください"
-"wrongUsernameOrPassword" = "ユーザー名、パスワード、または二段階認証コードが無効です。"  
+"wrongUsernameOrPassword" = "ユーザー名、パスワード、または二段階認証コードが無効です。"
 "successLogin" = "アカウントに正常にログインしました。"
 
 [pages.index]
@@ -565,9 +565,9 @@
 
 [pages.settings.security]
 "admin" = "管理者の資格情報"
-"twoFactor" = "二段階認証"  
-"twoFactorEnable" = "2FAを有効化"  
-"twoFactorEnableDesc" = "セキュリティを強化するために追加の認証層を追加します。"  
+"twoFactor" = "二段階認証"
+"twoFactorEnable" = "2FAを有効化"
+"twoFactorEnableDesc" = "セキュリティを強化するために追加の認証層を追加します。"
 "twoFactorModalSetTitle" = "二段階認証を有効にする"
 "twoFactorModalDeleteTitle" = "二段階認証を無効にする"
 "twoFactorModalSteps" = "二段階認証を設定するには、次の手順を実行してください:"
@@ -663,6 +663,7 @@
 "active" = "💡 有効:{{ .Enable }}\r\n"
 "enabled" = "🚨 有効化済み:{{ .Enable }}\r\n"
 "online" = "🌐 接続ステータス:{{ .Status }}\r\n"
+"lastOnline" = "🔙 最終オンライン: {{ .Time }}\r\n"
 "email" = "📧 メール:{{ .Email }}\r\n"
 "upload" = "🔼 アップロード↑:{{ .Upload }}\r\n"
 "download" = "🔽 ダウンロード↓:{{ .Download }}\r\n"
@@ -688,9 +689,9 @@
 "inbound_client_data_id" = "🔄 インバウンド: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 メール: {{ .ClientEmail }}\n📊 トラフィック: {{ .ClientTraffic }}\n📅 有効期限: {{ .ClientExp }}\n🌐 IP制限: {{ .IpLimit }}\n💬 コメント: {{ .ClientComment }}\n\n今すぐこのクライアントをインバウンドに追加できます!"
 "inbound_client_data_pass" = "🔄 インバウンド: {{ .InboundRemark }}\n\n🔑 パスワード: {{ .ClientPass }}\n📧 メール: {{ .ClientEmail }}\n📊 トラフィック: {{ .ClientTraffic }}\n📅 有効期限: {{ .ClientExp }}\n🌐 IP制限: {{ .IpLimit }}\n💬 コメント: {{ .ClientComment }}\n\n今すぐこのクライアントをインバウンドに追加できます!"
 "cancel" = "❌ プロセスがキャンセルされました!\n\nいつでも /start で再開できます。 🔄"
-"error_add_client"  = "⚠️ エラー:\n\n {{ .error }}"
-"using_default_value"  = "わかりました、デフォルト値を使用します。 😊"
-"incorrect_input" ="入力が無効です。\nフレーズはスペースなしで続けて入力してください。\n正しい例: aaaaaa\n間違った例: aaa aaa 🚫"
+"error_add_client" = "⚠️ エラー:\n\n {{ .error }}"
+"using_default_value" = "わかりました、デフォルト値を使用します。 😊"
+"incorrect_input" = "入力が無効です。\nフレーズはスペースなしで続けて入力してください。\n正しい例: aaaaaa\n間違った例: aaa aaa 🚫"
 "AreYouSure" = "本当にいいですか?🤔"
 "SuccessResetTraffic" = "📧 メール: {{ .ClientEmail }}\n🏁 結果: ✅ 成功"
 "FailedResetTraffic" = "📧 メール: {{ .ClientEmail }}\n🏁 結果: ❌ 失敗 \n\n🛠️ エラー: [ {{ .ErrorMessage }} ]"

+ 9 - 8
web/translation/translate.pt_BR.toml

@@ -106,12 +106,12 @@
 "invalidFormData" = "O formato dos dados de entrada é inválido."
 "emptyUsername" = "Nome de usuário é obrigatório"
 "emptyPassword" = "Senha é obrigatória"
-"wrongUsernameOrPassword" = "Nome de usuário, senha ou código de dois fatores inválido."  
+"wrongUsernameOrPassword" = "Nome de usuário, senha ou código de dois fatores inválido."
 "successLogin" = "Você entrou na sua conta com sucesso."
 
 [pages.index]
 "title" = "Visão Geral"
-"cpu" = "CPU" 
+"cpu" = "CPU"
 "logicalProcessors" = "Processadores lógicos"
 "frequency" = "Frequência"
 "swap" = "Swap"
@@ -565,9 +565,9 @@
 
 [pages.settings.security]
 "admin" = "Credenciais de administrador"
-"twoFactor" = "Autenticação de dois fatores"  
-"twoFactorEnable" = "Ativar 2FA"  
-"twoFactorEnableDesc" = "Adiciona uma camada extra de autenticação para mais segurança."  
+"twoFactor" = "Autenticação de dois fatores"
+"twoFactorEnable" = "Ativar 2FA"
+"twoFactorEnableDesc" = "Adiciona uma camada extra de autenticação para mais segurança."
 "twoFactorModalSetTitle" = "Ativar autenticação de dois fatores"
 "twoFactorModalDeleteTitle" = "Desativar autenticação de dois fatores"
 "twoFactorModalSteps" = "Para configurar a autenticação de dois fatores, siga alguns passos:"
@@ -663,6 +663,7 @@
 "active" = "💡 Ativo: {{ .Enable }}\r\n"
 "enabled" = "🚨 Ativado: {{ .Enable }}\r\n"
 "online" = "🌐 Status da conexão: {{ .Status }}\r\n"
+"lastOnline" = "🔙 Última vez online: {{ .Time }}\r\n"
 "email" = "📧 Email: {{ .Email }}\r\n"
 "upload" = "🔼 Upload: ↑{{ .Upload }}\r\n"
 "download" = "🔽 Download: ↓{{ .Download }}\r\n"
@@ -688,9 +689,9 @@
 "inbound_client_data_id" = "🔄 Entrada: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Tráfego: {{ .ClientTraffic }}\n📅 Data de expiração: {{ .ClientExp }}\n🌐 Limite de IP: {{ .IpLimit }}\n💬 Comentário: {{ .ClientComment }}\n\nAgora você pode adicionar o cliente à entrada!"
 "inbound_client_data_pass" = "🔄 Entrada: {{ .InboundRemark }}\n\n🔑 Senha: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Tráfego: {{ .ClientTraffic }}\n📅 Data de expiração: {{ .ClientExp }}\n🌐 Limite de IP: {{ .IpLimit }}\n💬 Comentário: {{ .ClientComment }}\n\nAgora você pode adicionar o cliente à entrada!"
 "cancel" = "❌ Processo Cancelado! \n\nVocê pode iniciar novamente a qualquer momento com /start. 🔄"
-"error_add_client"  = "⚠️ Erro:\n\n {{ .error }}"
-"using_default_value"  = "Tudo bem, vou manter o valor padrão. 😊"
-"incorrect_input" ="Sua entrada não é válida.\nAs frases devem ser contínuas, sem espaços.\nExemplo correto: aaaaaa\nExemplo incorreto: aaa aaa 🚫"
+"error_add_client" = "⚠️ Erro:\n\n {{ .error }}"
+"using_default_value" = "Tudo bem, vou manter o valor padrão. 😊"
+"incorrect_input" = "Sua entrada não é válida.\nAs frases devem ser contínuas, sem espaços.\nExemplo correto: aaaaaa\nExemplo incorreto: aaa aaa 🚫"
 "AreYouSure" = "Você tem certeza? 🤔"
 "SuccessResetTraffic" = "📧 Email: {{ .ClientEmail }}\n🏁 Resultado: ✅ Sucesso"
 "FailedResetTraffic" = "📧 Email: {{ .ClientEmail }}\n🏁 Resultado: ❌ Falhou \n\n🛠️ Erro: [ {{ .ErrorMessage }} ]"

+ 1 - 0
web/translation/translate.ru_RU.toml

@@ -663,6 +663,7 @@
 "active" = "💡 Активен: {{ .Enable }}\r\n"
 "enabled" = "🚨 Активен: {{ .Enable }}\r\n"
 "online" = "🌐 Статус соединения: {{ .Status }}\r\n"
+"lastOnline" = "🔙 Был(а) в сети: {{ .Time }}\r\n"
 "email" = "📧 Email: {{ .Email }}\r\n"
 "upload" = "🔼 Исходящий трафик: ↑{{ .Upload }}\r\n"
 "download" = "🔽 Входящий трафик: ↓{{ .Download }}\r\n"

+ 8 - 7
web/translation/translate.tr_TR.toml

@@ -106,7 +106,7 @@
 "invalidFormData" = "Girdi verisi formatı geçersiz."
 "emptyUsername" = "Kullanıcı adı gerekli"
 "emptyPassword" = "Şifre gerekli"
-"wrongUsernameOrPassword" = "Geçersiz kullanıcı adı, şifre veya iki adımlı doğrulama kodu."  
+"wrongUsernameOrPassword" = "Geçersiz kullanıcı adı, şifre veya iki adımlı doğrulama kodu."
 "successLogin" = "Hesabınıza başarıyla giriş yaptınız."
 
 [pages.index]
@@ -565,9 +565,9 @@
 
 [pages.settings.security]
 "admin" = "Yönetici kimlik bilgileri"
-"twoFactor" = "İki adımlı doğrulama"  
-"twoFactorEnable" = "2FA'yı Etkinleştir"  
-"twoFactorEnableDesc" = "Daha fazla güvenlik için ek bir doğrulama katmanı ekler."  
+"twoFactor" = "İki adımlı doğrulama"
+"twoFactorEnable" = "2FA'yı Etkinleştir"
+"twoFactorEnableDesc" = "Daha fazla güvenlik için ek bir doğrulama katmanı ekler."
 "twoFactorModalSetTitle" = "İki adımlı doğrulamayı etkinleştir"
 "twoFactorModalDeleteTitle" = "İki adımlı doğrulamayı devre dışı bırak"
 "twoFactorModalSteps" = "İki adımlı doğrulamayı ayarlamak için şu adımları izleyin:"
@@ -663,6 +663,7 @@
 "active" = "💡 Aktif: {{ .Enable }}\r\n"
 "enabled" = "🚨 Etkin: {{ .Enable }}\r\n"
 "online" = "🌐 Bağlantı durumu: {{ .Status }}\r\n"
+"lastOnline" = "🔙 Son çevrimiçi: {{ .Time }}\r\n"
 "email" = "📧 E-posta: {{ .Email }}\r\n"
 "upload" = "🔼 Yükleme: ↑{{ .Upload }}\r\n"
 "download" = "🔽 İndirme: ↓{{ .Download }}\r\n"
@@ -688,9 +689,9 @@
 "inbound_client_data_id" = "🔄 Giriş: {{ .InboundRemark }}\n\n🔑 Kimlik: {{ .ClientId }}\n📧 E-posta: {{ .ClientEmail }}\n📊 Trafik: {{ .ClientTraffic }}\n📅 Bitiş Tarihi: {{ .ClientExp }}\n🌐 IP Sınırı: {{ .IpLimit }}\n💬 Yorum: {{ .ClientComment }}\n\nArtık bu müşteriyi girişe ekleyebilirsin!"
 "inbound_client_data_pass" = "🔄 Giriş: {{ .InboundRemark }}\n\n🔑 Şifre: {{ .ClientPass }}\n📧 E-posta: {{ .ClientEmail }}\n📊 Trafik: {{ .ClientTraffic }}\n📅 Bitiş Tarihi: {{ .ClientExp }}\n🌐 IP Sınırı: {{ .IpLimit }}\n💬 Yorum: {{ .ClientComment }}\n\nArtık bu müşteriyi girişe ekleyebilirsin!"
 "cancel" = "❌ İşlem iptal edildi! \n\nİstediğiniz zaman /start ile yeniden başlayabilirsiniz. 🔄"
-"error_add_client"  = "⚠️ Hata:\n\n {{ .error }}"
-"using_default_value"  = "Tamam, varsayılan değeri kullanacağım. 😊"
-"incorrect_input" ="Girdiğiniz değer geçerli değil.\nKelime öbekleri boşluk olmadan devam etmelidir.\nDoğru örnek: aaaaaa\nYanlış örnek: aaa aaa 🚫"
+"error_add_client" = "⚠️ Hata:\n\n {{ .error }}"
+"using_default_value" = "Tamam, varsayılan değeri kullanacağım. 😊"
+"incorrect_input" = "Girdiğiniz değer geçerli değil.\nKelime öbekleri boşluk olmadan devam etmelidir.\nDoğru örnek: aaaaaa\nYanlış örnek: aaa aaa 🚫"
 "AreYouSure" = "Emin misin? 🤔"
 "SuccessResetTraffic" = "📧 E-posta: {{ .ClientEmail }}\n🏁 Sonuç: ✅ Başarılı"
 "FailedResetTraffic" = "📧 E-posta: {{ .ClientEmail }}\n🏁 Sonuç: ❌ Başarısız \n\n🛠️ Hata: [ {{ .ErrorMessage }} ]"

+ 8 - 7
web/translation/translate.uk_UA.toml

@@ -106,7 +106,7 @@
 "invalidFormData" = "Формат вхідних даних недійсний."
 "emptyUsername" = "Потрібне ім'я користувача"
 "emptyPassword" = "Потрібен пароль"
-"wrongUsernameOrPassword" = "Невірне ім’я користувача, пароль або код двофакторної аутентифікації."  
+"wrongUsernameOrPassword" = "Невірне ім’я користувача, пароль або код двофакторної аутентифікації."
 "successLogin" = "Ви успішно увійшли до свого облікового запису."
 
 [pages.index]
@@ -565,9 +565,9 @@
 
 [pages.settings.security]
 "admin" = "Облікові дані адміністратора"
-"twoFactor" = "Двофакторна аутентифікація"  
-"twoFactorEnable" = "Увімкнути 2FA"  
-"twoFactorEnableDesc" = "Додає додатковий рівень аутентифікації для підвищення безпеки."  
+"twoFactor" = "Двофакторна аутентифікація"
+"twoFactorEnable" = "Увімкнути 2FA"
+"twoFactorEnableDesc" = "Додає додатковий рівень аутентифікації для підвищення безпеки."
 "twoFactorModalSetTitle" = "Увімкнути двофакторну аутентифікацію"
 "twoFactorModalDeleteTitle" = "Вимкнути двофакторну аутентифікацію"
 "twoFactorModalSteps" = "Щоб налаштувати двофакторну аутентифікацію, виконайте кілька кроків:"
@@ -663,6 +663,7 @@
 "active" = "💡 Активний: {{ .Enable }}\r\n"
 "enabled" = "🚨 Увімкнено: {{ .Enable }}\r\n"
 "online" = "🌐 Стан підключення: {{ .Status }}\r\n"
+"lastOnline" = "🔙 Був(ла) онлайн: {{ .Time }}\r\n"
 "email" = "📧 Електронна пошта: {{ .Email }}\r\n"
 "upload" = "🔼 Upload: ↑{{ .Upload }}\r\n"
 "download" = "🔽 Download: ↓{{ .Download }}\r\n"
@@ -688,9 +689,9 @@
 "inbound_client_data_id" = "🔄 Вхід: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Електронна пошта: {{ .ClientEmail }}\n📊 Трафік: {{ .ClientTraffic }}\n📅 Дата завершення: {{ .ClientExp }}\n🌐 Обмеження IP: {{ .IpLimit }}\n💬 Коментар: {{ .ClientComment }}\n\nТепер ви можете додати клієнта до вхідного з'єднання!"
 "inbound_client_data_pass" = "🔄 Вхід: {{ .InboundRemark }}\n\n🔑 Пароль: {{ .ClientPass }}\n📧 Електронна пошта: {{ .ClientEmail }}\n📊 Трафік: {{ .ClientTraffic }}\n📅 Дата завершення: {{ .ClientExp }}\n🌐 Обмеження IP: {{ .IpLimit }}\n💬 Коментар: {{ .ClientComment }}\n\nТепер ви можете додати клієнта до вхідного з'єднання!"
 "cancel" = "❌ Процес скасовано! \n\nВи можете знову розпочати, використовуючи /start у будь-який час. 🔄"
-"error_add_client"  = "⚠️ Помилка:\n\n {{ .error }}"
-"using_default_value"  = "Гаразд, залишу значення за замовчуванням. 😊"
-"incorrect_input" ="Ваш ввід невірний.\nФрази повинні бути без пробілів.\nПравильний приклад: aaaaaa\nНеправильний приклад: aaa aaa 🚫"
+"error_add_client" = "⚠️ Помилка:\n\n {{ .error }}"
+"using_default_value" = "Гаразд, залишу значення за замовчуванням. 😊"
+"incorrect_input" = "Ваш ввід невірний.\nФрази повинні бути без пробілів.\nПравильний приклад: aaaaaa\nНеправильний приклад: aaa aaa 🚫"
 "AreYouSure" = "Ви впевнені? 🤔"
 "SuccessResetTraffic" = "📧 Електронна пошта: {{ .ClientEmail }}\n🏁 Результат: ✅ Успішно"
 "FailedResetTraffic" = "📧 Електронна пошта: {{ .ClientEmail }}\n🏁 Результат: ❌ Невдача \n\n🛠️ Помилка: [ {{ .ErrorMessage }} ]"

+ 4 - 3
web/translation/translate.vi_VN.toml

@@ -663,6 +663,7 @@
 "active" = "💡 Đang hoạt động: {{ .Enable }}\r\n"
 "enabled" = "🚨 Đã bật: {{ .Enable }}\r\n"
 "online" = "🌐 Trạng thái kết nối: {{ .Status }}\r\n"
+"lastOnline" = "🔙 Lần online gần nhất: {{ .Time }}\r\n"
 "email" = "📧 Email: {{ .Email }}\r\n"
 "upload" = "🔼 Tải lên: ↑{{ .Upload }}\r\n"
 "download" = "🔽 Tải xuống: ↓{{ .Download }}\r\n"
@@ -688,9 +689,9 @@
 "inbound_client_data_id" = "🔄 Kết nối vào: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Dung lượng: {{ .ClientTraffic }}\n📅 Ngày hết hạn: {{ .ClientExp }}\n🌐 Giới hạn IP: {{ .IpLimit }}\n💬 Ghi chú: {{ .ClientComment }}\n\nBây giờ bạn có thể thêm khách hàng vào inbound!"
 "inbound_client_data_pass" = "🔄 Kết nối vào: {{ .InboundRemark }}\n\n🔑 Mật khẩu: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Dung lượng: {{ .ClientTraffic }}\n📅 Ngày hết hạn: {{ .ClientExp }}\n🌐 Giới hạn IP: {{ .IpLimit }}\n💬 Ghi chú: {{ .ClientComment }}\n\nBây giờ bạn có thể thêm khách hàng vào inbound!"
 "cancel" = "❌ Quá trình đã bị hủy! \n\nBạn có thể bắt đầu lại bất cứ lúc nào bằng cách nhập /start. 🔄"
-"error_add_client"  = "⚠️ Lỗi:\n\n {{ .error }}"
-"using_default_value"  = "Được rồi, tôi sẽ sử dụng giá trị mặc định. 😊"
-"incorrect_input" ="Dữ liệu bạn nhập không hợp lệ.\nCác chuỗi phải liền mạch và không có dấu cách.\nVí dụ đúng: aaaaaa\nVí dụ sai: aaa aaa 🚫"
+"error_add_client" = "⚠️ Lỗi:\n\n {{ .error }}"
+"using_default_value" = "Được rồi, tôi sẽ sử dụng giá trị mặc định. 😊"
+"incorrect_input" = "Dữ liệu bạn nhập không hợp lệ.\nCác chuỗi phải liền mạch và không có dấu cách.\nVí dụ đúng: aaaaaa\nVí dụ sai: aaa aaa 🚫"
 "AreYouSure" = "Bạn có chắc không? 🤔"
 "SuccessResetTraffic" = "📧 Email: {{ .ClientEmail }}\n🏁 Kết quả: ✅ Thành công"
 "FailedResetTraffic" = "📧 Email: {{ .ClientEmail }}\n🏁 Kết quả: ❌ Thất bại \n\n🛠️ Lỗi: [ {{ .ErrorMessage }} ]"

+ 9 - 8
web/translation/translate.zh_CN.toml

@@ -106,7 +106,7 @@
 "invalidFormData" = "数据格式错误"
 "emptyUsername" = "请输入用户名"
 "emptyPassword" = "请输入密码"
-"wrongUsernameOrPassword" = "用户名、密码或双重验证码无效。"  
+"wrongUsernameOrPassword" = "用户名、密码或双重验证码无效。"
 "successLogin" = "您已成功登录您的账户。"
 
 [pages.index]
@@ -242,7 +242,7 @@
 "same" = "相同"
 "inboundData" = "入站数据"
 "exportInbound" = "导出入站规则"
-"import"="导入"
+"import" = "导入"
 "importInbound" = "导入入站规则"
 "periodicTrafficResetTitle" = "流量重置"
 "periodicTrafficResetDesc" = "按指定间隔自动重置流量计数器"
@@ -565,9 +565,9 @@
 
 [pages.settings.security]
 "admin" = "管理员凭据"
-"twoFactor" = "双重验证"  
-"twoFactorEnable" = "启用2FA"  
-"twoFactorEnableDesc" = "增加额外的验证层以提高安全性。"  
+"twoFactor" = "双重验证"
+"twoFactorEnable" = "启用2FA"
+"twoFactorEnableDesc" = "增加额外的验证层以提高安全性。"
 "twoFactorModalSetTitle" = "启用双重认证"
 "twoFactorModalDeleteTitle" = "停用双重认证"
 "twoFactorModalSteps" = "要设定双重认证,请执行以下步骤:"
@@ -663,6 +663,7 @@
 "active" = "💡 激活:{{ .Enable }}\r\n"
 "enabled" = "🚨 已启用:{{ .Enable }}\r\n"
 "online" = "🌐 连接状态:{{ .Status }}\r\n"
+"lastOnline" = "🔙 上次在线: {{ .Time }}\r\n"
 "email" = "📧 邮箱:{{ .Email }}\r\n"
 "upload" = "🔼 上传↑:{{ .Upload }}\r\n"
 "download" = "🔽 下载↓:{{ .Download }}\r\n"
@@ -688,9 +689,9 @@
 "inbound_client_data_id" = "🔄 入站: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 邮箱: {{ .ClientEmail }}\n📊 流量: {{ .ClientTraffic }}\n📅 到期日期: {{ .ClientExp }}\n🌐 IP 限制: {{ .IpLimit }}\n💬 备注: {{ .ClientComment }}\n\n你现在可以将客户添加到入站了!"
 "inbound_client_data_pass" = "🔄 入站: {{ .InboundRemark }}\n\n🔑 密码: {{ .ClientPass }}\n📧 邮箱: {{ .ClientEmail }}\n📊 流量: {{ .ClientTraffic }}\n📅 到期日期: {{ .ClientExp }}\n🌐 IP 限制: {{ .IpLimit }}\n💬 备注: {{ .ClientComment }}\n\n你现在可以将客户添加到入站了!"
 "cancel" = "❌ 进程已取消!\n\n您可以随时使用 /start 重新开始。 🔄"
-"error_add_client"  = "⚠️ 错误:\n\n {{ .error }}"
-"using_default_value"  = "好的,我会使用默认值。 😊"
-"incorrect_input" ="您的输入无效。\n短语应连续输入,不能有空格。\n正确示例: aaaaaa\n错误示例: aaa aaa 🚫"
+"error_add_client" = "⚠️ 错误:\n\n {{ .error }}"
+"using_default_value" = "好的,我会使用默认值。 😊"
+"incorrect_input" = "您的输入无效。\n短语应连续输入,不能有空格。\n正确示例: aaaaaa\n错误示例: aaa aaa 🚫"
 "AreYouSure" = "你确定吗?🤔"
 "SuccessResetTraffic" = "📧 邮箱: {{ .ClientEmail }}\n🏁 结果: ✅ 成功"
 "FailedResetTraffic" = "📧 邮箱: {{ .ClientEmail }}\n🏁 结果: ❌ 失败 \n\n🛠️ 错误: [ {{ .ErrorMessage }} ]"

+ 9 - 8
web/translation/translate.zh_TW.toml

@@ -106,7 +106,7 @@
 "invalidFormData" = "資料格式錯誤"
 "emptyUsername" = "請輸入使用者名稱"
 "emptyPassword" = "請輸入密碼"
-"wrongUsernameOrPassword" = "用戶名、密碼或雙重驗證碼無效。"  
+"wrongUsernameOrPassword" = "用戶名、密碼或雙重驗證碼無效。"
 "successLogin" = "您已成功登入您的帳戶。"
 
 [pages.index]
@@ -242,7 +242,7 @@
 "same" = "相同"
 "inboundData" = "入站資料"
 "exportInbound" = "匯出入站規則"
-"import"="匯入"
+"import" = "匯入"
 "importInbound" = "匯入入站規則"
 "periodicTrafficResetTitle" = "流量重置"
 "periodicTrafficResetDesc" = "按指定間隔自動重置流量計數器"
@@ -565,9 +565,9 @@
 
 [pages.settings.security]
 "admin" = "管理員憑證"
-"twoFactor" = "雙重驗證"  
-"twoFactorEnable" = "啟用2FA"  
-"twoFactorEnableDesc" = "增加額外的驗證層以提高安全性。"  
+"twoFactor" = "雙重驗證"
+"twoFactorEnable" = "啟用2FA"
+"twoFactorEnableDesc" = "增加額外的驗證層以提高安全性。"
 "twoFactorModalSetTitle" = "啟用雙重認證"
 "twoFactorModalDeleteTitle" = "停用雙重認證"
 "twoFactorModalSteps" = "要設定雙重認證,請執行以下步驟:"
@@ -663,6 +663,7 @@
 "active" = "💡 啟用:{{ .Enable }}\r\n"
 "enabled" = "🚨 已啟用:{{ .Enable }}\r\n"
 "online" = "🌐 連線狀態:{{ .Status }}\r\n"
+"lastOnline" = "🔙 上次上線: {{ .Time }}\r\n"
 "email" = "📧 郵箱:{{ .Email }}\r\n"
 "upload" = "🔼 上傳↑:{{ .Upload }}\r\n"
 "download" = "🔽 下載↓:{{ .Download }}\r\n"
@@ -688,9 +689,9 @@
 "inbound_client_data_id" = "🔄 入站: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 電子郵件: {{ .ClientEmail }}\n📊 流量: {{ .ClientTraffic }}\n📅 到期日: {{ .ClientExp }}\n🌐 IP 限制: {{ .IpLimit }}\n💬 備註: {{ .ClientComment }}\n\n你現在可以將客戶加入入站了!"
 "inbound_client_data_pass" = "🔄 入站: {{ .InboundRemark }}\n\n🔑 密碼: {{ .ClientPass }}\n📧 電子郵件: {{ .ClientEmail }}\n📊 流量: {{ .ClientTraffic }}\n📅 到期日: {{ .ClientExp }}\n🌐 IP 限制: {{ .IpLimit }}\n💬 備註: {{ .ClientComment }}\n\n你現在可以將客戶加入入站了!"
 "cancel" = "❌ 程序已取消!\n\n您可以隨時使用 /start 重新開始。 🔄"
-"error_add_client"  = "⚠️ 錯誤:\n\n {{ .error }}"
-"using_default_value"  = "好的,我會使用預設值。 😊"
-"incorrect_input" ="您的輸入無效。\n短語應連續輸入,不能有空格。\n正確示例: aaaaaa\n錯誤示例: aaa aaa 🚫"
+"error_add_client" = "⚠️ 錯誤:\n\n {{ .error }}"
+"using_default_value" = "好的,我會使用預設值。 😊"
+"incorrect_input" = "您的輸入無效。\n短語應連續輸入,不能有空格。\n正確示例: aaaaaa\n錯誤示例: aaa aaa 🚫"
 "AreYouSure" = "你確定嗎?🤔"
 "SuccessResetTraffic" = "📧 電子郵件: {{ .ClientEmail }}\n🏁 結果: ✅ 成功"
 "FailedResetTraffic" = "📧 電子郵件: {{ .ClientEmail }}\n🏁 結果: ❌ 失敗 \n\n🛠️ 錯誤: [ {{ .ErrorMessage }} ]"

+ 35 - 19
x-ui.sh

@@ -509,12 +509,16 @@ enable_bbr() {
     ubuntu | debian | armbian)
         apt-get update && apt-get install -yqq --no-install-recommends ca-certificates
         ;;
-    centos | rhel | almalinux | rocky | ol)
-        yum -y update && yum -y install ca-certificates
-        ;;
-    fedora | amzn | virtuozzo)
+    fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
         dnf -y update && dnf -y install ca-certificates
         ;;
+    centos)
+            if [[ "${VERSION_ID}" =~ ^7 ]]; then
+                yum -y update && yum -y install ca-certificates
+            else
+                dnf -y update && dnf -y install ca-certificates
+            fi
+        ;;
     arch | manjaro | parch)
         pacman -Sy --noconfirm ca-certificates
         ;;
@@ -1073,12 +1077,15 @@ ssl_cert_issue() {
     ubuntu | debian | armbian)
         apt-get update && apt-get install socat -y
         ;;
-    centos | rhel | almalinux | rocky | ol)
-        yum -y update && yum -y install socat
-        ;;
-    fedora | amzn | virtuozzo)
+    fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
         dnf -y update && dnf -y install socat
         ;;
+    centos)
+            if [[ "${VERSION_ID}" =~ ^7 ]]; then
+                yum -y update && yum -y install socat
+            else
+                dnf -y update && dnf -y install socat
+            fi
     arch | manjaro | parch)
         pacman -Sy --noconfirm socat
         ;;
@@ -1086,7 +1093,7 @@ ssl_cert_issue() {
         zypper refresh && zypper -q install -y socat
         ;;
     alpine)
-        apk add socat
+        apk add socat curl openssl
         ;;
     *)
         echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n"
@@ -1537,13 +1544,17 @@ install_iplimit() {
         armbian)
             apt-get update && apt-get install fail2ban -y
             ;;
-        centos | rhel | almalinux | rocky | ol)
-            yum update -y && yum install epel-release -y
-            yum -y install fail2ban
-            ;;
-        fedora | amzn | virtuozzo)
+        fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
             dnf -y update && dnf -y install fail2ban
             ;;
+        centos)
+            if [[ "${VERSION_ID}" =~ ^7 ]]; then
+                yum update -y && yum install epel-release -y
+                yum -y install fail2ban
+            else
+                dnf -y update && dnf -y install fail2ban
+            fi
+            ;;
         arch | manjaro | parch)
             pacman -Syu --noconfirm fail2ban
             ;;
@@ -1637,14 +1648,19 @@ remove_iplimit() {
             apt-get purge -y fail2ban -y
             apt-get autoremove -y
             ;;
-        centos | rhel | almalinux | rocky | ol)
-            yum remove fail2ban -y
-            yum autoremove -y
-            ;;
-        fedora | amzn | virtuozzo)
+        fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
             dnf remove fail2ban -y
             dnf autoremove -y
             ;;
+        centos)
+            if [[ "${VERSION_ID}" =~ ^7 ]]; then    
+                yum remove fail2ban -y
+                yum autoremove -y
+            else
+                dnf remove fail2ban -y
+                dnf autoremove -y
+            fi
+            ;;
         arch | manjaro | parch)
             pacman -Rns --noconfirm fail2ban
             ;;