build-sspanel-appprofile.ts 7.3 KB

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