From 25ff0949ce8a42c9847776f3f5b097e5204b2a2e Mon Sep 17 00:00:00 2001 From: infosave2007 Date: Sat, 24 Jan 2026 13:03:05 +0300 Subject: [PATCH] fix(xray): Fix X-Ray install script and QR code generation - Fix docker run command in install script (use single line instead of backslash continuations which break when stored in MySQL) - Handle new xray x25519 output format that uses 'Password' instead of 'Public key' - Make addClientToServer method public for backup restore functionality - Created migration 046 with complete fix for X-Ray VLESS protocol --- inc/VpnClient.php | 34 +++++++++++- migrations/046_fix_xray_docker_run.sql | 77 ++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 migrations/046_fix_xray_docker_run.sql diff --git a/inc/VpnClient.php b/inc/VpnClient.php index 671a6c4..3011f6f 100644 --- a/inc/VpnClient.php +++ b/inc/VpnClient.php @@ -200,7 +200,7 @@ class VpnClient if (isset($extras['result']) && is_array($extras['result'])) { $extras = array_merge($extras, $extras['result']); } - + foreach ($extras as $k => $v) { if (is_scalar($v)) { // Preserve uppercase for AWG obfuscation parameters @@ -834,7 +834,7 @@ class VpnClient /** * Add client to server using wg set (more reliable than syncconf) */ - private static function addClientToServer(array $serverData, string $publicKey, string $clientIP): void + public static function addClientToServer(array $serverData, string $publicKey, string $clientIP): void { $containerName = $serverData['container_name']; $presharedKey = $serverData['preshared_key']; @@ -936,6 +936,36 @@ class VpnClient require_once __DIR__ . '/QrUtil.php'; try { + // Check for X-Ray VLESS + if (strpos($config, 'vless://') === 0) { + // Parse VLESS URI + $parsed = parse_url($config); + // Allow missing user (UUID) and port for partial configs + if ($parsed && isset($parsed['host'])) { + $host = $parsed['host']; + $port = isset($parsed['port']) ? (int) $parsed['port'] : 443; + $clientId = $parsed['user'] ?? ''; + $fragment = $parsed['fragment'] ?? ''; + + parse_str($parsed['query'] ?? '', $query); + + $reality = null; + if (($query['security'] ?? '') === 'reality') { + $reality = [ + 'publicKey' => $query['pbk'] ?? '', + 'serverName' => $query['sni'] ?? '', + 'shortId' => $query['sid'] ?? '', + 'fingerprint' => $query['fp'] ?? 'chrome' + ]; + } + + // Use QrUtil to encode correct X-Ray payload + $payloadXray = QrUtil::encodeXrayPayload($host, $port, $clientId, $fragment, $reality); + return QrUtil::pngBase64($payloadXray); + } + } + + // Fallback for WireGuard / default // Use old Amnezia format with Qt/QDataStream encoding $payloadOld = QrUtil::encodeOldPayloadFromConf($config); $dataUri = QrUtil::pngBase64($payloadOld); diff --git a/migrations/046_fix_xray_docker_run.sql b/migrations/046_fix_xray_docker_run.sql new file mode 100644 index 0000000..c788a9f --- /dev/null +++ b/migrations/046_fix_xray_docker_run.sql @@ -0,0 +1,77 @@ +-- Fix X-Ray install script: +-- 1) Use single-line docker run (backslash continuations break in MySQL) +-- 2) Handle new xray x25519 output format (Password instead of Public key) +UPDATE protocols +SET install_script = '#!/bin/bash +set -euo pipefail + +CONTAINER_NAME="${CONTAINER_NAME:-amnezia-xray}" +XRAY_PORT=${SERVER_PORT:-443} + +docker pull teddysun/xray >/dev/null 2>&1 || true + +GEN=$(docker run --rm --entrypoint /usr/bin/xray teddysun/xray x25519 2>/dev/null || true) +PRIVATE_KEY=$(printf "%s\n" "$GEN" | sed -n -E "s/^[Pp]rivate[Kk]ey:[[:space:]]*(.*)$/\\1/p" | tr -d " \\t\\r\\n") +if [ -z "$PRIVATE_KEY" ]; then + PRIVATE_KEY=$(printf "%s\n" "$GEN" | grep -i "private" | head -1 | sed "s/.*:[[:space:]]*//" | tr -d " \\t\\r\\n") +fi +PUBLIC_KEY=$(printf "%s\n" "$GEN" | sed -n -E "s/^[Pp]ublic[[:space:]]*[Kk]ey:[[:space:]]*(.*)$/\\1/p" | tr -d " \\t\\r\\n") +if [ -z "$PUBLIC_KEY" ]; then + PUBLIC_KEY=$(printf "%s\n" "$GEN" | sed -n -E "s/^[Pp]assword:[[:space:]]*(.*)$/\\1/p" | tr -d " \\t\\r\\n") +fi +if [ -z "$PUBLIC_KEY" ] && [ -n "$PRIVATE_KEY" ]; then + PUBLIC_KEY=$(docker run --rm --entrypoint /usr/bin/xray teddysun/xray x25519 -i "$PRIVATE_KEY" 2>/dev/null | sed -n -E "s/^[Pp]assword:[[:space:]]*(.*)$/\\1/p" | tr -d " \\t\\r\\n" || true) +fi + +SHORT_ID=$(od -An -tx1 -N8 /dev/urandom | tr -d " \\n") +CLIENT_ID=$(cat /proc/sys/kernel/random/uuid) +SERVER_NAME="${SERVER_NAME:-www.googletagmanager.com}" +FINGERPRINT="${FINGERPRINT:-chrome}" +SPIDER_X="${SPIDER_X:-/}" + +docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true +mkdir -p /opt/amnezia/xray + +cat > /opt/amnezia/xray/server.json <