fix(qr): Generate full X-Ray Client config JSON to match Native Amnezia format

This commit is contained in:
infosave2007
2026-01-24 14:56:13 +03:00
parent fdbb18c9df
commit de10268ab4
2 changed files with 53 additions and 24 deletions
+50 -22
View File
@@ -409,38 +409,66 @@ class QrUtil
return json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); return json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
} }
public static function encodeXrayPayload(string $host, int $port, string $clientId, string $description = '', ?array $reality = null, string $rawConfig = ''): string public static function encodeXrayPayload(string $host, int $port, string $clientId, string $description = '', ?array $reality = null, string $rawConfig = '', string $flow = ''): string
{ {
$desc = $description !== '' ? $description : self::resolveServerDescription($host); $desc = $description !== '' ? $description : self::resolveServerDescription($host);
// Instead of generating a JSON config, we wrap the raw VLESS URI in a "config" field. // Construct full Client XRay config (Amnezia native format expects this structure)
// This matches how WireGuard configs are handled in master branch and is likely what Amnezia expects. $outbound = [
// If rawConfig is not provided, we reconstruct a basic VLESS URI (fallback) 'protocol' => 'vless',
if (empty($rawConfig)) { 'settings' => [
// Basic reconstruction if needed, but we should pass valid rawConfig from VpnClient 'vnext' => [
$security = ($reality && isset($reality['publicKey']) && $reality['publicKey'] !== '') ? 'reality' : 'none'; [
$type = 'tcp'; 'address' => $host,
$flow = ($security === 'reality') ? 'xtls-rprx-vision' : ''; 'port' => $port,
'users' => [
[
'id' => $clientId,
'encryption' => 'none'
]
]
]
]
],
'streamSettings' => [
'network' => 'tcp',
'security' => ($reality ? 'reality' : 'none')
]
];
$query = http_build_query([ if ($flow !== '') {
'security' => $security, $outbound['settings']['vnext'][0]['users'][0]['flow'] = $flow;
'type' => $type,
'flow' => $flow,
'sni' => $reality['serverName'] ?? '',
'pbk' => $reality['publicKey'] ?? '',
'fp' => $reality['fingerprint'] ?? 'chrome',
'sid' => $reality['shortId'] ?? ''
]);
$rawConfig = "vless://$clientId@$host:$port?$query";
} }
if ($reality) {
$outbound['streamSettings']['realitySettings'] = [
'fingerprint' => $reality['fingerprint'] ?? 'chrome',
'serverName' => $reality['serverName'] ?? '',
'publicKey' => $reality['publicKey'] ?? '',
'shortId' => $reality['shortId'] ?? '',
'spiderX' => ''
];
}
$fullConfig = [
'log' => ['loglevel' => 'warning'],
'inbounds' => [
[
'listen' => '127.0.0.1',
'port' => 10808,
'protocol' => 'socks',
'settings' => ['udp' => true]
]
],
'outbounds' => [$outbound]
];
$envelope = [ $envelope = [
'containers' => [ 'containers' => [
[ [
'xray' => [ 'xray' => [
'isThirdPartyConfig' => true, // No isThirdPartyConfig flag - treats as native container
// Pass raw VLESS URI directly, without JSON wrapper 'last_config' => json_encode($fullConfig, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT),
'last_config' => $rawConfig,
'port' => (string) $port, 'port' => (string) $port,
'transport_proto' => 'tcp' 'transport_proto' => 'tcp'
], ],
+3 -2
View File
@@ -970,6 +970,7 @@ class VpnClient
$fragment = $parsed['fragment'] ?? ''; $fragment = $parsed['fragment'] ?? '';
parse_str($parsed['query'] ?? '', $query); parse_str($parsed['query'] ?? '', $query);
$flow = $query['flow'] ?? '';
$reality = null; $reality = null;
if (($query['security'] ?? '') === 'reality') { if (($query['security'] ?? '') === 'reality') {
@@ -981,8 +982,8 @@ class VpnClient
]; ];
} }
// Use QrUtil to encode correct X-Ray payload // Use QrUtil to encode correct X-Ray payload (Native Amnezia Client Config)
$payloadXray = QrUtil::encodeXrayPayload($host, $port, $clientId, $fragment, $reality, $config); $payloadXray = QrUtil::encodeXrayPayload($host, $port, $clientId, $fragment, $reality, $config, $flow);
return QrUtil::pngBase64($payloadXray); return QrUtil::pngBase64($payloadXray);
} }
} }