build-sspanel-appprofile.ts 7.8 KB

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