Clash.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Services\Subscribe;
  4. use App\Services\Subscribe;
  5. use function array_merge;
  6. use function json_decode;
  7. use function yaml_emit;
  8. use const YAML_UTF8_ENCODING;
  9. final class Clash extends Base
  10. {
  11. public function getContent($user): string
  12. {
  13. $nodes = [];
  14. $clash_config = $_ENV['Clash_Config'];
  15. $clash_group_indexes = $_ENV['Clash_Group_Indexes'];
  16. $clash_group_config = $_ENV['Clash_Group_Config'];
  17. $nodes_raw = Subscribe::getUserNodes($user);
  18. foreach ($nodes_raw as $node_raw) {
  19. $node_custom_config = json_decode($node_raw->custom_config, true);
  20. switch ((int) $node_raw->sort) {
  21. case 0:
  22. $plugin = $node_custom_config['plugin'] ?? '';
  23. $plugin_option = $node_custom_config['plugin_option'] ?? null;
  24. // Clash 特定配置
  25. $udp = $node_custom_config['udp'] ?? true;
  26. $node = [
  27. 'name' => $node_raw->name,
  28. 'type' => 'ss',
  29. 'server' => $node_raw->server,
  30. 'port' => (int) $user->port,
  31. 'password' => $user->passwd,
  32. 'cipher' => $user->method,
  33. 'udp' => (bool) $udp,
  34. 'plugin' => $plugin,
  35. 'plugin-opts' => $plugin_option,
  36. ];
  37. break;
  38. case 1:
  39. $ss_2022_port = $node_custom_config['offset_port_user'] ??
  40. ($node_custom_config['offset_port_node'] ?? 443);
  41. $method = $node_custom_config['method'] ?? '2022-blake3-aes-128-gcm';
  42. $pk_len = match ($method) {
  43. '2022-blake3-aes-128-gcm' => 16,
  44. default => 32,
  45. };
  46. $user_pk = $user->getSs2022Pk($pk_len);
  47. // Clash 特定配置
  48. $udp = $node_custom_config['udp'] ?? true;
  49. $node = [
  50. 'name' => $node_raw->name,
  51. 'type' => 'ss',
  52. 'server' => $node_raw->server,
  53. 'port' => (int) $ss_2022_port,
  54. 'password' => $user_pk,
  55. 'cipher' => $method,
  56. 'udp' => (bool) $udp,
  57. ];
  58. break;
  59. case 2:
  60. $tuic_port = $node_custom_config['offset_port_user'] ??
  61. ($node_custom_config['offset_port_node'] ?? 443);
  62. $host = $node_custom_config['host'] ?? '';
  63. $congestion_control = $node_custom_config['congestion_control'] ?? 'bbr';
  64. // Only Clash.Meta core has TUIC support
  65. // Tuic V5 Only
  66. $node = [
  67. 'name' => $node_raw->name,
  68. 'type' => 'tuic',
  69. 'server' => $node_raw->server,
  70. 'port' => (int) $tuic_port,
  71. 'password' => $user->passwd,
  72. 'uuid' => $user->uuid,
  73. 'sni' => $host,
  74. 'congestion-controller' => $congestion_control,
  75. 'reduce-rtt' => true,
  76. ];
  77. break;
  78. case 11:
  79. $v2_port = $node_custom_config['offset_port_user'] ??
  80. ($node_custom_config['offset_port_node'] ?? 443);
  81. $security = $node_custom_config['security'] ?? 'none';
  82. $encryption = $node_custom_config['encryption'] ?? 'auto';
  83. $network = $node_custom_config['network'] ?? '';
  84. $host = $node_custom_config['header']['request']['headers']['Host'][0] ??
  85. $node_custom_config['host'] ?? '';
  86. $allow_insecure = $node_custom_config['allow_insecure'] ?? false;
  87. $tls = $security === 'tls';
  88. // Clash 特定配置
  89. $udp = $node_custom_config['udp'] ?? true;
  90. $ws_opts = $node_custom_config['ws-opts'] ?? $node_custom_config['ws_opts'] ?? null;
  91. $h2_opts = $node_custom_config['h2-opts'] ?? $node_custom_config['h2_opts'] ?? null;
  92. $http_opts = $node_custom_config['http-opts'] ?? $node_custom_config['http_opts'] ?? null;
  93. $grpc_opts = $node_custom_config['grpc-opts'] ?? $node_custom_config['grpc_opts'] ?? null;
  94. // HTTPUpgrade 在 Clash.Meta 内核中属于 ws 类型
  95. if ($network === 'httpupgrade') {
  96. $network = 'ws';
  97. }
  98. $node = [
  99. 'name' => $node_raw->name,
  100. 'type' => 'vmess',
  101. 'server' => $node_raw->server,
  102. 'port' => (int) $v2_port,
  103. 'uuid' => $user->uuid,
  104. 'alterId' => 0,
  105. 'cipher' => $encryption,
  106. 'udp' => (bool) $udp,
  107. 'tls' => $tls,
  108. 'skip-cert-verify' => (bool) $allow_insecure,
  109. 'servername' => $host,
  110. 'network' => $network,
  111. 'ws-opts' => $ws_opts,
  112. 'h2-opts' => $h2_opts,
  113. 'http-opts' => $http_opts,
  114. 'grpc-opts' => $grpc_opts,
  115. ];
  116. break;
  117. case 14:
  118. $trojan_port = $node_custom_config['offset_port_user'] ??
  119. ($node_custom_config['offset_port_node'] ?? 443);
  120. $network = $node_custom_config['header']['type'] ?? $node_custom_config['network'] ?? 'tcp';
  121. $host = $node_custom_config['host'] ?? '';
  122. $allow_insecure = $node_custom_config['allow_insecure'] ?? false;
  123. // Clash 特定配置
  124. $udp = $node_custom_config['udp'] ?? true;
  125. $ws_opts = $node_custom_config['ws-opts'] ?? $node_custom_config['ws_opts'] ?? null;
  126. $grpc_opts = $node_custom_config['grpc-opts'] ?? $node_custom_config['grpc_opts'] ?? null;
  127. // HTTPUpgrade 在 Clash.Meta 内核中属于 ws 类型
  128. if ($network === 'httpupgrade') {
  129. $network = 'ws';
  130. }
  131. $node = [
  132. 'name' => $node_raw->name,
  133. 'type' => 'trojan',
  134. 'server' => $node_raw->server,
  135. 'sni' => $host,
  136. 'port' => (int) $trojan_port,
  137. 'password' => $user->uuid,
  138. 'network' => $network,
  139. 'udp' => (bool) $udp,
  140. 'skip-cert-verify' => (bool) $allow_insecure,
  141. 'ws-opts' => $ws_opts,
  142. 'grpc-opts' => $grpc_opts,
  143. ];
  144. break;
  145. default:
  146. $node = [];
  147. break;
  148. }
  149. if ($node === []) {
  150. continue;
  151. }
  152. $nodes[] = $node;
  153. foreach ($clash_group_indexes as $index) {
  154. $clash_group_config['proxy-groups'][$index]['proxies'][] = $node_raw->name;
  155. }
  156. }
  157. $clash_nodes = [
  158. 'proxies' => $nodes,
  159. ];
  160. return yaml_emit(
  161. array_merge($clash_config, $clash_nodes, $clash_group_config),
  162. YAML_UTF8_ENCODING
  163. );
  164. }
  165. }