build-sspanel-appprofile.ts 9.0 KB

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