build-sspanel-appprofile.ts 7.7 KB

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