build-sspanel-appprofile.ts 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. import { getAppleCdnDomainsPromise } from './build-apple-cdn';
  2. import { getDomesticAndDirectDomainsRulesetPromise } from './build-domestic-direct-lan-ruleset-dns-mapping-module';
  3. import { surgeRulesetToClashClassicalTextRuleset, surgeDomainsetToClashRuleset } from './lib/clash';
  4. import { readFileIntoProcessedArray } from './lib/fetch-text-by-line';
  5. import { task } from './trace';
  6. import path from 'path';
  7. import { ALL as AllStreamServices } from '../Source/stream';
  8. import { getChnCidrPromise } from './build-chn-cidr';
  9. import { getTelegramCIDRPromise } from './build-telegram-cidr';
  10. import { compareAndWriteFile } from './lib/create-file';
  11. import { getMicrosoftCdnRulesetPromise } from './build-microsoft-cdn';
  12. import { isTruthy } from './lib/misc';
  13. import { appendArrayInPlace } from './lib/append-array-in-place';
  14. const POLICY_GROUPS: Array<[name: string, insertProxy: boolean, insertDirect: boolean]> = [
  15. ['Default Proxy', true, false],
  16. ['Global', true, true],
  17. ['Microsoft & Apple', true, true],
  18. ['Stream', true, false],
  19. ['Steam Download', true, true],
  20. ['Domestic', false, true],
  21. ['Final Match', true, true]
  22. ];
  23. const removeNoResolved = (line: string) => line.replace(',no-resolve', '');
  24. /**
  25. * This only generates a simplified version, for under-used users only.
  26. */
  27. export const buildSSPanelUIMAppProfile = task(typeof Bun !== 'undefined' ? Bun.main === __filename : require.main === module, __filename)(async (span) => {
  28. const [
  29. [domesticDomains, directDomains, lanDomains],
  30. appleCdnDomains,
  31. microsoftCdnDomains,
  32. appleCnDomains,
  33. neteaseMusicDomains,
  34. microsoftDomains,
  35. appleDomains,
  36. streamDomains,
  37. steamDomains,
  38. globalDomains,
  39. telegramDomains,
  40. domesticCidrs,
  41. streamCidrs,
  42. { results: rawTelegramCidrs },
  43. lanCidrs
  44. ] = await Promise.all([
  45. // domestic - domains
  46. getDomesticAndDirectDomainsRulesetPromise()
  47. .then(
  48. data => (
  49. data.map(surgeRulesetToClashClassicalTextRuleset)
  50. ) as [string[], string[], string[]]
  51. ),
  52. getAppleCdnDomainsPromise().then(domains => domains.map(domain => `DOMAIN-SUFFIX,${domain}`)),
  53. getMicrosoftCdnRulesetPromise().then(surgeRulesetToClashClassicalTextRuleset),
  54. readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/apple_cn.conf')),
  55. readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/neteasemusic.conf')).then(surgeRulesetToClashClassicalTextRuleset),
  56. // microsoft & apple - domains
  57. readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/microsoft.conf')),
  58. readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/apple_services.conf')).then(surgeRulesetToClashClassicalTextRuleset),
  59. // stream - domains
  60. surgeRulesetToClashClassicalTextRuleset(AllStreamServices.flatMap((i) => i.rules)),
  61. // steam - domains
  62. readFileIntoProcessedArray(path.resolve(__dirname, '../Source/domainset/steam.conf')).then(surgeDomainsetToClashRuleset),
  63. // global - domains
  64. readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/global.conf')).then(surgeRulesetToClashClassicalTextRuleset),
  65. readFileIntoProcessedArray(path.resolve(__dirname, '../Source/non_ip/telegram.conf')).then(surgeRulesetToClashClassicalTextRuleset),
  66. // domestic - ip cidr
  67. getChnCidrPromise().then(cidrs => cidrs.map(cidr => `IP-CIDR,${cidr}`)),
  68. AllStreamServices.flatMap((i) => (
  69. i.ip
  70. ? [
  71. ...i.ip.v4.map((ip) => `IP-CIDR,${ip}`),
  72. ...i.ip.v6.map((ip) => `IP-CIDR6,${ip}`)
  73. ]
  74. : []
  75. )),
  76. // global - ip cidr
  77. getTelegramCIDRPromise(),
  78. // lan - ip cidr
  79. readFileIntoProcessedArray(path.resolve(__dirname, '../Source/ip/lan.conf'))
  80. ] as const);
  81. const telegramCidrs = rawTelegramCidrs.map(removeNoResolved);
  82. const output = generateAppProfile(
  83. [
  84. ...domesticDomains,
  85. ...appleCdnDomains,
  86. ...microsoftCdnDomains,
  87. ...appleCnDomains,
  88. ...neteaseMusicDomains
  89. ],
  90. [
  91. ...microsoftDomains,
  92. ...appleDomains
  93. ],
  94. streamDomains,
  95. steamDomains,
  96. [
  97. ...globalDomains,
  98. ...telegramDomains
  99. ],
  100. [
  101. ...directDomains,
  102. ...lanDomains
  103. ],
  104. domesticCidrs,
  105. streamCidrs,
  106. [
  107. ...telegramCidrs
  108. ],
  109. lanCidrs
  110. );
  111. await compareAndWriteFile(
  112. span,
  113. output,
  114. path.resolve(__dirname, '../Internal/appprofile.php')
  115. );
  116. });
  117. function generateAppProfile(
  118. directDomains: string[],
  119. microsoftAppleDomains: string[],
  120. streamDomains: string[],
  121. steamDomains: string[],
  122. globalDomains: string[],
  123. lanDomains: string[],
  124. directCidrs: string[],
  125. streamCidrs: string[],
  126. globalCidrs: string[],
  127. lanCidrs: string[]
  128. ) {
  129. const redults = [
  130. '<?php',
  131. '',
  132. `// # Build ${new Date().toISOString()}`,
  133. '',
  134. 'declare(strict_types=1);',
  135. '',
  136. '$_ENV[\'Clash_Config\'] = [',
  137. ' \'port\' => 7890,',
  138. ' \'socks-port\' => 7891,',
  139. ' \'allow-lan\' => false,',
  140. ' \'mode\' => \'Rule\',',
  141. ' \'ipv6\' => true,',
  142. ' \'log-level\' => \'error\',',
  143. ' \'external-controller\' => \'0.0.0.0:9090\',',
  144. ' \'tun\' => [',
  145. ' \'enable\' => true,',
  146. ' \'stack\' => \'system\',',
  147. ' \'auto-route\' => true,',
  148. ' \'auto-redir\' => true,',
  149. ' \'auto-detect-interface\' => true,',
  150. ' \'dns-hijack\' => [',
  151. ' \'8.8.8.8:53\',',
  152. ' \'any:53\',',
  153. ' \'tcp://8.8.8.8:53\',',
  154. ' \'tcp://any:53\',',
  155. ' ]',
  156. ' ]',
  157. '];',
  158. '',
  159. `$_ENV['Clash_Group_Indexes'] = [${JSON.stringify(POLICY_GROUPS.reduce<number[]>((acc, [, insertProxy], index) => {
  160. if (insertProxy) {
  161. acc.push(index);
  162. }
  163. return acc;
  164. }, [])).slice(1, -1)}];`,
  165. '$_ENV[\'Clash_Group_Config\'] = [',
  166. ' \'proxy-groups\' => ['
  167. ];
  168. appendArrayInPlace(
  169. redults,
  170. POLICY_GROUPS.flatMap(([name, insertProxy, insertDirect]) => {
  171. return [
  172. ' [',
  173. ` 'name' => '${name}',`,
  174. ' \'type\' => \'select\',',
  175. ' \'proxies\' => [',
  176. insertProxy && name !== 'Default Proxy' && ' \'Default Proxy\',',
  177. insertDirect && ' \'DIRECT\',',
  178. ' ],',
  179. ' ],'
  180. ].filter(isTruthy);
  181. })
  182. );
  183. appendArrayInPlace(
  184. redults,
  185. [
  186. ' ],',
  187. ' \'rules\' => ['
  188. ]
  189. );
  190. // domestic - domains
  191. appendArrayInPlace(
  192. redults,
  193. directDomains.map(line => ` '${line},Domestic',`)
  194. );
  195. // microsoft & apple - domains
  196. appendArrayInPlace(
  197. redults,
  198. microsoftAppleDomains.map(line => ` '${line},Microsoft & Apple',`)
  199. );
  200. // stream - domains
  201. appendArrayInPlace(
  202. redults,
  203. streamDomains.map(line => ` '${line},Stream',`)
  204. );
  205. // steam download - domains
  206. appendArrayInPlace(
  207. redults,
  208. steamDomains.map(line => ` '${line},Steam Download',`)
  209. );
  210. // global - domains
  211. appendArrayInPlace(
  212. redults,
  213. globalDomains.map(line => ` '${line},Global',`)
  214. );
  215. // microsoft & apple - ip cidr (nope)
  216. // lan - domains
  217. appendArrayInPlace(
  218. redults,
  219. lanDomains.map(line => ` '${line},DIRECT',`)
  220. );
  221. // stream - ip cidr
  222. appendArrayInPlace(
  223. redults,
  224. streamCidrs.map(line => ` '${line},Stream',`)
  225. );
  226. // global - ip cidr
  227. appendArrayInPlace(
  228. redults,
  229. globalCidrs.map(line => ` '${line},Global',`)
  230. );
  231. // domestic - ip cidr
  232. appendArrayInPlace(
  233. redults,
  234. directCidrs.map(line => ` '${line},Domestic',`)
  235. );
  236. // lan - ip cidr
  237. appendArrayInPlace(
  238. redults,
  239. lanCidrs.map(line => ` '${line},DIRECT',`)
  240. );
  241. // match
  242. appendArrayInPlace(
  243. redults,
  244. [
  245. ' \'MATCH,Final Match\',',
  246. ' ],',
  247. '];'
  248. ]
  249. );
  250. return redults;
  251. }