feat: Добавлена веб-панель управления VPN-прокси и Docker-конфигурация.
This commit is contained in:
@@ -1,101 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Usage: ./gen-client-from-url.sh "vless://uuid@host:443?type=tcp&security=reality&pbk=PUBLIC_KEY&fp=random&sni=yahoo.com&sid=SHORTID&spx=%2F&flow=xtls-rprx-vision#tag" [output.json]
|
||||
# If output not set, defaults to client.json
|
||||
|
||||
URL_INPUT=${1:-}
|
||||
OUT_FILE=${2:-client.json}
|
||||
TEMPLATE_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
TEMPLATE_FILE="$TEMPLATE_DIR/client.template.json"
|
||||
|
||||
if [[ -z "$URL_INPUT" ]]; then
|
||||
echo "Error: provide VLESS reality URL or Subscription URL" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$TEMPLATE_FILE" ]]; then
|
||||
echo "Template not found: $TEMPLATE_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if input starts with vless://
|
||||
if [[ "$URL_INPUT" != vless://* ]]; then
|
||||
echo "Error: Only vless:// URLs are supported." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Strip scheme
|
||||
URL_NOSCHEME=${URL_INPUT#vless://}
|
||||
|
||||
UUID_HOST_PORT=${URL_NOSCHEME%%\?*}
|
||||
QUERY_AND_TAG=${URL_NOSCHEME#*?}
|
||||
QUERY=${QUERY_AND_TAG%%#*}
|
||||
TAG_RAW=${URL_INPUT#*#}
|
||||
TAG=${TAG_RAW:-reality}
|
||||
|
||||
UUID=${UUID_HOST_PORT%%@*}
|
||||
HOST_PORT=${UUID_HOST_PORT#*@}
|
||||
HOST=${HOST_PORT%%:*}
|
||||
PORT=${HOST_PORT##*:}
|
||||
|
||||
# Parse query params (portable, no associative arrays)
|
||||
PBK=""; FINGERPRINT="chrome"; SNI=""; SHORT_ID=""; SPX=""; FLOW=""
|
||||
OLD_IFS=$IFS
|
||||
IFS='&'
|
||||
set +u
|
||||
for kv in $QUERY; do
|
||||
key=${kv%%=*}
|
||||
val=${kv#*=}
|
||||
case "$key" in
|
||||
pbk) PBK=$val ;;
|
||||
fp) FINGERPRINT=$val ;;
|
||||
sni) SNI=$val ;;
|
||||
sid) SHORT_ID=$val ;;
|
||||
spx) SPX=$val ;;
|
||||
flow) FLOW=$val ;;
|
||||
esac
|
||||
done
|
||||
set -u
|
||||
IFS=$OLD_IFS
|
||||
SNI=${SNI:-$HOST}
|
||||
# SPX currently not used
|
||||
|
||||
if [[ -z "$UUID" || -z "$HOST" || -z "$PORT" || -z "$PBK" || -z "$SHORT_ID" ]]; then
|
||||
echo "Missing required fields (uuid/host/port/pbk/sid)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TMP=$(mktemp)
|
||||
cp "$TEMPLATE_FILE" "$TMP"
|
||||
|
||||
# Perform replacements safely using jq
|
||||
# Replace simple placeholders
|
||||
jq \
|
||||
--arg uuid "$UUID" \
|
||||
--arg server "$HOST" \
|
||||
--argjson port "$PORT" \
|
||||
--arg tag "$TAG" \
|
||||
--arg sni "$SNI" \
|
||||
--arg fp "$FINGERPRINT" \
|
||||
--arg pk "$PBK" \
|
||||
--arg sid "$SHORT_ID" \
|
||||
--arg flow "$FLOW" '
|
||||
(.outbounds[] | select(.type=="vless")) as $v | (
|
||||
.outbounds |= map(if .type=="vless" then (
|
||||
.uuid=$uuid
|
||||
| .server=$server
|
||||
| .server_port=$port
|
||||
| .tag=$tag
|
||||
| .tls.server_name=$sni
|
||||
| .tls.utls.fingerprint=$fp
|
||||
| .tls.reality.public_key=$pk
|
||||
| .tls.reality.short_id=$sid
|
||||
| .flow=$flow
|
||||
) else . end)
|
||||
| .route.final=$tag
|
||||
)' "$TMP" > "$OUT_FILE"
|
||||
|
||||
rm "$TMP"
|
||||
|
||||
echo "Generated $OUT_FILE from URL (tag=$TAG)"
|
||||
101
scripts/menu.sh
101
scripts/menu.sh
@@ -1,101 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -u
|
||||
|
||||
URL_INPUT=${1:-}
|
||||
CONFIG_FILE="client.json"
|
||||
|
||||
if [[ -z "$URL_INPUT" ]]; then
|
||||
echo "Usage: ./menu.sh <VLESS_URL_or_SUBSCRIPTION_URL>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to decode URL params specially for VLESS
|
||||
decode_url() {
|
||||
local encoded="$1"
|
||||
# Basic URL decode
|
||||
echo -e "${encoded//%/\\x}"
|
||||
}
|
||||
|
||||
# 1. Detect type
|
||||
if [[ "$URL_INPUT" =~ ^vless:// ]]; then
|
||||
echo "Direct VLESS URL detected. Applying..."
|
||||
./gen-client-from-url.sh "$URL_INPUT" "$CONFIG_FILE"
|
||||
echo "Triggering reload..."
|
||||
curl -s http://localhost:9090/reload
|
||||
echo "Done."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 2. It's likely a subscription
|
||||
echo "Fetching subscription..."
|
||||
SUB_CONTENT=$(curl -sSL "$URL_INPUT")
|
||||
|
||||
if [[ -z "$SUB_CONTENT" ]]; then
|
||||
echo "Error: Empty response."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Try Base64 decode
|
||||
if DECODED=$(echo "$SUB_CONTENT" | base64 -d 2>/dev/null); then
|
||||
echo "Subscription is Base64 encoded."
|
||||
RAW_LIST="$DECODED"
|
||||
else
|
||||
echo "Subscription is plain text."
|
||||
RAW_LIST="$SUB_CONTENT"
|
||||
fi
|
||||
|
||||
# 3. Parse VLESS links
|
||||
# We will use an array to store links and names
|
||||
declare -a LINKS
|
||||
declare -a NAMES
|
||||
|
||||
i=0
|
||||
while IFS= read -r line; do
|
||||
# trimming
|
||||
line=$(echo "$line" | xargs)
|
||||
if [[ "$line" =~ ^vless:// ]]; then
|
||||
LINKS[$i]="$line"
|
||||
|
||||
# Extract name from hash #Name
|
||||
if [[ "$line" =~ \#(.*)$ ]]; then
|
||||
NAME=$(decode_url "${BASH_REMATCH[1]}")
|
||||
else
|
||||
NAME="Config_$((i+1))"
|
||||
fi
|
||||
NAMES[$i]="$NAME"
|
||||
((i++))
|
||||
fi
|
||||
done <<< "$RAW_LIST"
|
||||
|
||||
COUNT=${#LINKS[@]}
|
||||
|
||||
if [[ "$COUNT" -eq 0 ]]; then
|
||||
echo "No VLESS configs found in subscription."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 4. Display Menu
|
||||
echo "Found $COUNT configurations:"
|
||||
echo "--------------------------------"
|
||||
for (( j=0; j<COUNT; j++ )); do
|
||||
echo "$((j+1))) ${NAMES[$j]}"
|
||||
done
|
||||
echo "--------------------------------"
|
||||
read -p "Select config (1-$COUNT): " SELECTION
|
||||
|
||||
if ! [[ "$SELECTION" =~ ^[0-9]+$ ]] || [ "$SELECTION" -lt 1 ] || [ "$SELECTION" -gt "$COUNT" ]; then
|
||||
echo "Invalid selection."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INDEX=$((SELECTION-1))
|
||||
SELECTED_URL=${LINKS[$INDEX]}
|
||||
|
||||
echo "Selected: ${NAMES[$INDEX]}"
|
||||
echo "Applying..."
|
||||
|
||||
./gen-client-from-url.sh "$SELECTED_URL" "$CONFIG_FILE"
|
||||
|
||||
echo "Triggering process reload..."
|
||||
curl -s http://localhost:9090/reload
|
||||
echo "Success! Proxy updated."
|
||||
Reference in New Issue
Block a user