build-sspanel-appprofile.ts 8.4 KB

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