fix(qr): Generate full X-Ray Client config JSON to match Native Amnezia format
This commit is contained in:
+50
-22
@@ -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
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user