From 6202fab22122ac8bf00fb4c9102fbb628939785c Mon Sep 17 00:00:00 2001 From: Evgeny Nerush Date: Mon, 4 Dec 2023 01:08:04 +0300 Subject: [PATCH] bring better UX; refactor --- README.md | 16 ++ ex.sh | 713 +++++++++++++++++++++++++++++++----------------------- 2 files changed, 424 insertions(+), 305 deletions(-) diff --git a/README.md b/README.md index 9d6c17f..e81a66e 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,22 @@ Note also that for current client config, traffic to .cn, .ru, .by and .ir sites [here](https://github.com/EvgenyNerush/coherence-grabber) for details. This makes your server much less attention-grabbing and suspicious, but your connection less anonymous. +### More deep description?? + +Important: It is assumed that configs are stored and updated +locally as `config_server.json`, `config_client.json` or +`config_client_username.json` files. You should manually +start XRay with one of configs, depending +which role - server or client - XRay should play: +``` + sudo cp config_(role).json /usr/local/etc/xray/config.json + sudo systemctl start xray +``` +or +``` + sudo xray run -c config_(role).json +``` + ### Other clients For Windows, MacOS or Android you can try Nekobox, v2rayNG or ? (TODO): tests and config generation for them. diff --git a/ex.sh b/ex.sh index dad3811..ccf1ec1 100755 --- a/ex.sh +++ b/ex.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash +# stdout styles bold='\033[0;1m' underl='\033[0;4m' red='\033[0;31m' @@ -7,6 +8,10 @@ green='\033[0;32m' yellow='\033[0;33m' normal='\033[0m' +################# +### Functions ### +################# + # delete lines with comments from jsonC jsonc2json () { if [ ! -v $1 ] @@ -62,7 +67,7 @@ strip_quotes () { } # convert json string with statistics to pretty form; -# (!) use with pipe | to deal with multiline strings correctly +# use with pipe | to deal with multiline strings correctly! pretty_stats () { read stats if [ -v "$stats" ] @@ -74,112 +79,78 @@ pretty_stats () { fi } -export PATH=$PATH:/usr/local/bin/ # for sudo user this can be not in PATH -if command -v xray > /dev/null -then - xray_version=$(xray --version | head -n 1 | cut -c 6-10) - echo -e "${green}xray ${xray_version} detected${normal}" -fi - -if command -v jq > /dev/null -then - jq_installed=true - echo -e "${green}jq found${normal}" -else - jq_installed=false - echo -e "${yellow}Warning: jq not installed but needed for operations with configs${normal}" -fi - -if [ $(id -u) -eq 0 ] -then - is_root=true - echo -e "${green}running as root${normal}" -else - is_root=false - echo -e "${yellow}Warning: you should be root to install xray${normal}" -fi - -command="help" -if [ ! -v $1 ] -then - command=$1 -fi - -if [ $command = "install" ] -then - - echo -e "${bold}Download and install xray?${normal} (Y/n)" - read answer_di - if [ -v $answer_di ] || [ $(echo $answer_di | cut -c 1) != "n" ] +# check if the mandatory command exists +check_command () { + cmd=$1 + cmd_aim=$2 + comment=$3 + if command -v $cmd > /dev/null then - install_xray=true - if command -v xray > /dev/null - then - echo -e "xray ${version} detected, install anyway? (y/N)" - read answer_ia - if [ -v $answer_ia ] || ([ $(echo $answer_ia | cut -c 1) != "y" ] && [ $(echo $answer_ia | cut -c 1) != "Y" ]) - then - install_xray=false - fi - fi - if $install_xray - then - if $is_root - then - if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install - then - dat_dir="/usr/local/share/xray/" - mkdir -p $dat_dir - cp customgeo.dat ${dat_dir} - echo -e "${green}xray installed${normal}" - else - echo -e "${red}xray not installed, something goes wrong${normal}" - fi - else - echo -e "${red}You should be root, or run this script with sudo -to install xray${normal}" - exit 1 - fi - fi + echo -e "${green}${cmd} found${normal}" + else + echo -e "${red}${cmd} not found; ${cmd_aim}${normal}" + echo -e "${comment}" + exit 1 fi +} - echo -e "${bold}Generate configs?${normal} (Y/n)" - read answer_gc - if [ -v $answer_gc ] || [ $(echo $answer_gc | cut -c 1) != "n" ] +# make directory `dir`; if it already exists, first move it to dir.backup; +# if dir.backup already exists, first move it to dir.backup.backup; if it exists, +# first delete it +unsafe_mkdir () { + dir=$1 + if [ -d "$dir" ] then - if ! $(command -v xray > /dev/null) + if [ -d "${dir}.backup" ] then - echo -e "${red}xray not installed, can't generate configs" - exit 1 - fi - if ! $jq_installed - then - echo -e "${red}jq not installed, can't generate configs" - exit 1 - else - echo -e "${bold}Enter IPv4 or IPv6 address of your xray server, or its domain name:${normal}" - read address - id=$(xray uuid) # generate random uuid for vless - keys=$(xray x25519) - private_key=$(echo $keys | cut -d " " -f 3) - public_key=$(echo $keys | cut -d " " -f 6) - # generate random short_id for grpc-reality - if command -v openssl > /dev/null + if [ -d "${dir}.backup.backup" ] then - short_id=$(openssl rand -hex 8) - else - echo -e "Enter a random (up to) 16-digit hex number, -containing only digits 0-9 and letters a-f, for instance -1234567890abcdef" - read short_id - if [ -v $short_id ] - then - echo -e "${red}short id not set${normal}" - exit 1 - fi + rm -r "${dir}.backup.backup" fi - echo -e "${bold}Choose a fake site to mimic.${normal} -Better if it is popular and not blocked in your country: + mv "${dir}.backup" "${dir}.backup.backup" + [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" "${dir}.backup.backup" + fi + mv "$dir" "${dir}.backup" + [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" "${dir}.backup" + fi + mkdir "$dir" + [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" "${dir}" +} + +# copy file to file.backup with the same logic as in `unsafe_mkdir` +cp_to_backup () { + file=$1 + if [ -f "${file}.backup" ] + then + cp "${file}.backup" "${file}.backup.backup" + [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" "${file}.backup.backup" + fi + cp "$file" "${file}.backup" + [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" "${file}.backup" +} + +# the main part of `./ex.sh conf` command, generates config files for server and clients +conf () { + export PATH=$PATH:/usr/local/bin/ # brings xray to the path for sudo user + check_command xray "needed for config generation" "to install xray, try: sudo ./ex.sh install" + check_command jq "needed for operations with configs" + check_command openssl "needed for strong random numbers excluding some types of attacks" + # + echo -e "Enter IPv4 or IPv6 address of your xray server, or its domain name:" + read address + if [ -v $address ] + then + echo -e "${red}no address given${normal}" + exit 1 + fi + id=$(xray uuid) # random uuid for VLESS + keys=$(xray x25519) # string "Private key: Abc... Public key: Xyz..." + private_key=$(echo $keys | cut -d " " -f 3) # get 3rd field of fields delimited by spaces + public_key=$(echo $keys | cut -d " " -f 6) # get 6th field + short_id=$(openssl rand -hex 8) # random short_id for REALITY + # + echo -e "Choose a fake site to mimic. +Better if it is quite popular and not blocked in your country: (1) www.youtube.com (default) (2) www.microsoft.com (3) www.google.com @@ -189,208 +160,358 @@ Better if it is popular and not blocked in your country: (7) aws.amazon.com (8) discord.com (9) your variant" - read number - default_fake_site="www.youtube.com" - if [ ! -v $number ] + read number + default_fake_site="www.youtube.com" + if [ -v $number ] + then + fake_site=$default_fake_site + else + if [ $number -eq 2 ] + then + fake_site="www.microsoft.com" + elif [ $number -eq 3 ] + then + fake_site="www.google.com" + elif [ $number -eq 4 ] + then + fake_site="www.bing.com" + elif [ $number -eq 5 ] + then + fake_site="www.yahoo.com" + elif [ $number -eq 6 ] + then + fake_site="www.adobe.com" + elif [ $number -eq 7 ] + then + fake_site="aws.amazon.com" + elif [ $number -eq 8 ] + then + fake_site="discord.com" + elif [ $number -eq 9 ] + then + echo -e "type your variant:" + read fake_site + if [ -v $fake_site ] then - if [ $number -eq 2 ] - then - fake_site="www.microsoft.com" - elif [ $number -eq 3 ] - then - fake_site="www.google.com" - elif [ $number -eq 4 ] - then - fake_site="www.bing.com" - elif [ $number -eq 5 ] - then - fake_site="www.yahoo.com" - elif [ $number -eq 6 ] - then - fake_site="www.adobe.com" - elif [ $number -eq 7 ] - then - fake_site="aws.amazon.com" - elif [ $number -eq 8 ] - then - fake_site="discord.com" - elif [ $number -eq 9 ] - then - echo -e "type your variant:" - read fake_site - if [ -v $fake_site ] - then - fake_site=$default_fake_site - fi - else - fake_site=$default_fake_site - fi - else fake_site=$default_fake_site fi - server_names="[ \"$fake_site\" ]" - echo -e "${green}mimic ${fake_site}${normal}" - email="love@xray.com" - # make server config - jsonc2json template_config_server.jsonc \ - | jq ".inbounds[1].settings.clients[0].id=\"${id}\" - | .inbounds[2].settings.clients[0].id=\"${id}\" - | .inbounds[1].settings.clients[0].email=\"${email}\" - | .inbounds[2].settings.clients[0].email=\"${email}\" - | .inbounds[1].streamSettings.realitySettings.dest=\"${fake_site}:443\" - | .inbounds[2].streamSettings.realitySettings.dest=\"${fake_site}:80\" - | .inbounds[1].streamSettings.realitySettings.serverNames=${server_names} - | .inbounds[2].streamSettings.realitySettings.serverNames=${server_names} - | .inbounds[1].streamSettings.realitySettings.privateKey=\"${private_key}\" - | .inbounds[2].streamSettings.realitySettings.privateKey=\"${private_key}\" - | .inbounds[1].streamSettings.realitySettings.shortIds=[ \"${short_id}\" ] - | .inbounds[2].streamSettings.realitySettings.shortIds=[ \"${short_id}\" ]" \ - > config_server.json - # then make the user (not root) the owner of the file - [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" config_server.json - vnext=" [ - { - \"address\": \"${address}\", - \"port\": 443, - \"users\": [ - { - \"id\": \"${id}\", - \"email\": \"${email}\", - \"encryption\": \"none\", - \"flow\": \"xtls-rprx-vision\" - } - ] - } - ]" - clientRealitySettings=" { - \"fingerprint\": \"chrome\", - \"serverName\": \"${fake_site}\", - \"show\": false, - \"publicKey\": \"${public_key}\", - \"shortId\": \"${short_id}\", - }" - # make main client config - jsonc2json template_config_client.jsonc | jq ".outbounds |= map(if .settings.vnext then .settings.vnext=${vnext} else . end) | .outbounds |= map(if .streamSettings.realitySettings then .streamSettings.realitySettings=${clientRealitySettings} else . end)" > config_client.json - # then make the user (not root) an owner of a file - [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" config_client.json + else + fake_site=$default_fake_site fi fi + echo -e "${green}mimic ${fake_site}${normal}" + server_names="[ \"$fake_site\" ]" + email="love@xray.com" + # + unsafe_mkdir conf + ## Make server config ## + jsonc2json template_config_server.jsonc \ + | jq ".inbounds[1].settings.clients[0].id=\"${id}\" + | .inbounds[2].settings.clients[0].id=\"${id}\" + | .inbounds[1].settings.clients[0].email=\"${email}\" + | .inbounds[2].settings.clients[0].email=\"${email}\" + | .inbounds[1].streamSettings.realitySettings.dest=\"${fake_site}:443\" + | .inbounds[2].streamSettings.realitySettings.dest=\"${fake_site}:80\" + | .inbounds[1].streamSettings.realitySettings.serverNames=${server_names} + | .inbounds[2].streamSettings.realitySettings.serverNames=${server_names} + | .inbounds[1].streamSettings.realitySettings.privateKey=\"${private_key}\" + | .inbounds[2].streamSettings.realitySettings.privateKey=\"${private_key}\" + | .inbounds[1].streamSettings.realitySettings.shortIds=[ \"${short_id}\" ] + | .inbounds[2].streamSettings.realitySettings.shortIds=[ \"${short_id}\" ]" \ + > ./conf/config_server.json + # make the user (not root) the owner of the file + [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_server.json + vnext=" [ + { + \"address\": \"${address}\", + \"port\": 443, + \"users\": [ + { + \"id\": \"${id}\", + \"email\": \"${email}\", + \"encryption\": \"none\", + \"flow\": \"xtls-rprx-vision\" + } + ] + } + ]" + clientRealitySettings=" { + \"fingerprint\": \"chrome\", + \"serverName\": \"${fake_site}\", + \"show\": false, + \"publicKey\": \"${public_key}\", + \"shortId\": \"${short_id}\", + }" + ## Make main client config ## + jsonc2json template_config_client.jsonc \ + | jq ".outbounds + |= map(if .settings.vnext then .settings.vnext=${vnext} else . end) + | .outbounds + |= map(if .streamSettings.realitySettings then .streamSettings.realitySettings=${clientRealitySettings} else . end)" \ + > ./conf/config_client.json + # make the user (not root) an owner of a file + [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_client.json + if [ -f "./conf/config_client.json" ] && [ -f "./conf/config_server.json" ] + then + echo -e "${green}config files are generated${normal}" + else + echo -e "${red}config files are not generated${normal}" + fi +} -elif [ $command = "add" ] -then - echo -e "${bold}add${normal}" - if ! $(command -v xray > /dev/null) +# the main part of `./ex.sh add` command, adds config for given users and updates server config +add () { + export PATH=$PATH:/usr/local/bin/ # brings xray to the path for sudo user + check_command xray "needed for config generation" "to install xray, try: sudo ./ex.sh install" + check_command jq "needed for operations with configs" + check_command openssl "needed for strong random numbers excluding some types of attacks" + if [ ! -f "./conf/config_client.json" ] || [ ! -f "./conf/config_server.json" ] then - echo -e "${red}xray needed but not installed${normal}" + echo -e "${red}server config and config for default user are needed +but not present; to generate them, try + ./ex.sh conf${normal}" exit 1 fi - if ! $jq_installed + if [ -v $1 ] then - echo -e "${red}jq needed but not installed${normal}" - exit 1 - fi - if [ ! -f "config_client.json" ] || [ ! -r "config_server.json" ] - then - echo -e "${red}server config and config for default user are needed but not present, -first generate them with ${normal}install${red} command.${normal}" - exit 1 - fi - if [ -v $2 ] - then - echo -e "${red}username not set${normal} + echo -e "${red}usernames not set${normal} For default user, use config_client.json generated -by ${underl}install${normal} command. Otherwise use non-void username, +by ${underl}install${normal} command. Otherwise use non-void usernames, preferably of letters and digits only." exit 1 - else - username=$2 fi - configs=(config_client_*.json) - username_exists=false - for c in ${configs[@]} + # backup server config + cp_to_backup ./conf/config_server.json + # loop over usernames + for username in "$@" do - if [ -f $c ] - then - email=$(jq '.outbounds[0].settings.vnext[0].users[0].email' $c) + username_exists=false + client_emails=$(jq ".inbounds[1].settings.clients[].email" ./conf/config_server.json) + for email in ${client_emails[@]} + do + # convert "name@example.com" to name name=$(echo $email | cut -d "@" -f 1 | cut -c 2-) if [ $username = $name ] then username_exists=true fi - fi - done - if $username_exists - then - echo -e "${red}username ${username} already exists, try another one${normal}" - exit 1 - else - id=$(xray uuid) # generate random uuid for vless - # generate random short_id for grpc-reality - if command -v openssl > /dev/null + done + if $username_exists then - short_id=$(openssl rand -hex 8) + echo -e "${yellow}username ${username} already exists, no new config created fot it${normal}" else - echo -e "Enter a random (up to) 16-digit hex number, -containing only digits 0-9 and letters a-f, for instance -1234567890abcdef" - read short_id - if [ -v $short_id ] + id=$(xray uuid) # generate random uuid for vless + # generate random short_id for grpc-reality + short_id=$(openssl rand -hex 8) + # make new user config from default user config + ok1=$(cat ./conf/config_client.json | jq ".outbounds[0].settings.vnext[0].users[0].id=\"${id}\" | .outbounds[0].settings.vnext[0].users[0].email=\"${username}@example.com\" | .outbounds[0].streamSettings.realitySettings.shortId=\"${short_id}\"" > ./conf/config_client_${username}.json) + # then make the user (not root) an owner of a file + [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_client.json + # update server config + client=" + { + \"id\": \"${id}\", + \"email\": \"${username}@example.com\", + \"flow\": \"xtls-rprx-vision\" + } + " + # update server config from backup + cp ./conf/config_server.json ./conf/tmpconfig.json + ok2=$(cat ./conf/tmpconfig.json | jq ".inbounds[1].settings.clients += [${client}] | .inbounds[1].streamSettings.realitySettings.shortIds += [\"${short_id}\"]" > ./conf/config_server.json) + rm ./conf/tmpconfig.json + # then make the user (not root) an owner of a file + [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_server.json + if $ok1 && $ok2 then - echo -e "${red}short id not set${normal}" - exit 1 + echo -e "${green}config_client_${username}.json is written, config_server.json is updated${normal}" + else + echo -e "${red}something went wrong with username ${username}${normal}" fi fi - # make new user config from default user config - cat config_client.json | jq ".outbounds[0].settings.vnext[0].users[0].id=\"${id}\" | .outbounds[0].settings.vnext[0].users[0].email=\"${username}@example.com\" | .outbounds[0].streamSettings.realitySettings.shortId=\"${short_id}\"" > config_client_${username}.json - # then make the user (not root) an owner of a file - [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" config_client.json - # update server config - client=" - { - \"id\": \"${id}\", - \"email\": \"${username}@example.com\", - \"flow\": \"xtls-rprx-vision\" - } - " - cp config_server.json config_server.json.backup - # update server config - cat config_server.json.backup | jq ".inbounds[1].settings.clients += [${client}] | .inbounds[1].streamSettings.realitySettings.shortIds += [\"${short_id}\"]" > config_server.json - # then make the user (not root) an owner of a file - [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" config_server.json - echo -e "${green}config_client_${username}.json is written, -config_server.json is updated${normal}" + done +} + +# `./ex.sh push` command, copies config to xray's dir and restarts xray +push () { + if [ $(id -u) -ne 0 ] # not root + then + echo -e "${red}you should have root privileges for that, try +sudo ./ex.sh push${normal}" + exit 1 + fi + echo -e "Which config to use, server/client/other? (S/c/o)" + read answer + if [ ! -v $answer ] && [ ${answer::1} = "c" ] + then + # use main client config + config="config_client.json" + elif [ ! -v $answer ] && [ ${answer::1} = "o" ] + then + # use config of some other user + echo -e "Which config from ./conf/ to use? (write the filename)" + read answer + config="$answer" + else + # use server config + config="config_server.json" + fi + if $(cp ./conf/${config} /usr/local/etc/xray/config.json && systemctl restart xray) + then + sleep 1s # gives time to xray restart + journalctl -u xray | tail -n 5 # message about xray start + else + echo -e "${red}can't copy config or start xray, try +sudo xray run -c ./conf/${config}${normal}" + fi +} + +############# +### MAIN #### +############# + +command="help" # default +if [ ! -v $1 ] +then + command=$1 +fi + +if [ $command = "install" ] +then + if [ $(id -u) -ne 0 ] # not root + then + echo -e "${red}you should have root privileges to install xray, try +sudo ./ex.sh install${normal}" + exit 1 + fi + # + if command -v xray > /dev/null # xray already installed + then + echo -e "${yellow}xray ${version} detected, install anyway?${normal} (y/N)" + read answer + # default answer, answer not set or it's first letter is not `y` or `Y` + if [ -v $answer ] || ([ ${answer::1} != "y" ] && [ ${answer::1} != "Y" ]) + then + exit 1 + fi + fi + # + if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install + then + echo -e "${green}xray installed${normal}" + dat_dir="/usr/local/share/xray/" + mkdir -p $dat_dir + if cp customgeo.dat ${dat_dir} + then + echo -e "${green}customgeo.dat copied to ${dat_dir}${normal}" + else + echo -e "${red}customgeo.dat not copied to ${dat_dir}${normal}" + exit 1 + fi + else + echo -e "${red}xray not installed, something goes wrong${normal}" + exit 1 + fi + # + echo -e "Generate configs? (Y/n)" + read answer + if [ ! -v $answer ] && [ ${answer::1} = "n" ] + then + # config generation is not requested + echo -e "If you have a config file for xray, you can manually +start xray with the following commands: + sudo cp yourconfig.json /usr/local/etc/xray/config.json + sudo systemctl start xray +or + sudo xray run -c yourconfig.json" + exit 0 + else + # config generation is requested + conf + fi + # + echo -e "Add other users? (Y/n)" + read answer + if [ -v $answer ] || [ ${answer::1} != "n" ] + then + echo -e "Enter usernames separated by spaces" + read usernames + add $usernames + fi + # + echo -e "Copy config to xray's dir and restart xray? (Y/n)" + read answer + if [ -v $answer ] || [ ${answer::1} != "n" ] + then + push + fi + +elif [ $command = "conf" ] +then + conf + # + echo -e "Add other users? (Y/n)" + read answer + if [ -v $answer ] || [ ${answer::1} != "n" ] + then + echo -e "Enter usernames separated by spaces" + read usernames + add $usernames + fi + # + echo -e "Copy config to xray's dir and restart xray? (Y/n)" + read answer + if [ -v $answer ] || [ ${answer::1} != "n" ] + then + push + fi + +elif [ $command = "add" ] +then + add "${@:2}" + # + echo -e "Copy config to xray's dir and restart xray? (Y/n)" + read answer + if [ -v $answer ] || [ ${answer::1} != "n" ] + then + push fi elif [ $command = "del" ] then - echo -e "${bold}del${normal}" - if ! $jq_installed + check_command jq "needed for operations with configs" + if [ ! -f "./conf/config_server.json" ] then - echo -e "${red}jq needed but not installed${normal}" + echo -e "${red}server config not found" exit 1 fi - if [ -v $2 ] - then - echo -e "${red}username not set${normal}" - exit 1 - else - username=$2 - fi - config="config_client_${username}.json" - if [ ! -f $config ] - then - echo -e "${red}no config for user ${username}${normal}" - exit 1 - fi - short_id=$(jq ".outbounds[0].streamSettings.realitySettings.shortId" $config) - cp config_server.json config_server.json.backup - # update server config - cat config_server.json.backup | jq "del(.inbounds[1].settings.clients[] | select(.email == \"${username}@example.com\")) | del(.inbounds[1].streamSettings.realitySettings.shortIds[] | select(. == ${short_id}))" > config_server.json - # then make the user (not root) an owner of a file - [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" config_server.json - rm config_client_${username}.json - echo -e "${green}config_client_${username}.json is deleted, + # backup server config + cp_to_backup ./conf/config_server.json + # loop over usernames + for username in "${@:2}" + do + config="./conf/config_client_${username}.json" + if [ ! -f $config ] + then + echo -e "${yellow}no config for user ${username}${normal}" + else + short_id=$(jq ".outbounds[0].streamSettings.realitySettings.shortId" $config) + cp ./conf/config_server.json ./conf/tmpconfig.json + # update server config + cat ./conf/tmpconfig.json | jq "del(.inbounds[1].settings.clients[] | select(.email == \"${username}@example.com\")) | del(.inbounds[1].streamSettings.realitySettings.shortIds[] | select(. == ${short_id}))" > ./conf/config_server.json + rm ./conf/tmpconfig.json + # then make the user (not root) an owner of a file + [[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_server.json + rm config_client_${username}.json + echo -e "${green}config_client_${username}.json is deleted, config_server.json is updated${normal}" + fi + done + add + push + +elif [ $command = "push" ] +then + push elif [ $command = "stats" ] then @@ -454,26 +575,20 @@ then elif [ $command = "remove" ] then echo -e "Remove xray? (y/N)" - read answer_rx - if [ ! -v $answer_rx ] && ([ $(echo $answer_rx | cut -c 1) = "y" ] || [ $(echo $answer_rx | cut -c 1) = "Y" ]) + read answer + if [ ! -v $answer ] && [ ${answer::1} = "y" ] then - echo -e "${red}Please type YES to remove${normal}" - read answer_y - if [ ! -v $answer_y ] && ([ $answer_y = "YES" ] || [ $answer_y = "yes" ]) + if [ $(id -u) -ne 0 ] # not root then - if $is_root - then - if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove --purge - then - echo -e "${green}xray removed${normal}" - else - echo -e "${red}xray not removed${normal}" - fi - else - echo -e "${red}You should be root, or run this script with sudo -to remove xray${normal}" - exit 1 - fi + echo -e "${red}you should have root privileges for that, try +sudo ./ex.sh push${normal}" + exit 1 + fi + if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove --purge + then + echo -e "${green}xray removed${normal}" + else + echo -e "${red}xray not removed${normal}" fi fi @@ -483,30 +598,18 @@ ${green}**** Hi, there! How to use: ****${normal} ${bold}./ex.sh ${underl}command${normal} -Here is the list of all available commands: +Here is a list of all the commands available: ${bold}help${normal} show this message (default) ${bold}install${normal} run interactive prompt, which asks to download and install - XRay and generate configs for server and client - ${bold}add ${underl}username${normal} add user with (any, fake) username to configs - ${bold}del ${underl}username${normal} delete user with given username from configs + XRay and generate configs + ${bold}conf${normal} generate config files for server and clients + ${bold}add ${underl}usernames${normal} add users with (any, fake) usernames to configs + ${bold}del ${underl}usernames${normal} delete users with given usernames from configs + ${bold}push${normal} copy config to xray's dir and restarts xray ${bold}stats${normal} print some traffic statistics ${bold}stats reset${normal} print statistics then set them to zero ${bold}upgrade${normal} upgrade xray, do not touch configs ${bold}remove${normal} remove xray" fi -echo -e " -Command is done. - -${bold}Important:${normal} It is assumed that configs are stored and updated -locally as config_server.json, config_client.json or -config_client_username.json files. You should manually -start XRay with one of configs, depending -which role - server or client - XRay should play: - sudo cp config_(role).json /usr/local/etc/xray/config.json - sudo systemctl start xray -or - sudo xray run -c config_(role).json -" -