parse-filter.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. const { isIP } = require('net');
  2. const { default: got } = require('got-cjs');
  3. const rDomain = /^(((?!\-))(xn\-\-)?[a-z0-9\-_]{0,61}[a-z0-9]{1,1}\.)*(xn\-\-)?([a-z0-9\-]{1,61}|[a-z0-9\-]{1,30})\.[a-z]{2,}$/m
  4. /**
  5. * @param {string | URL} domainListsUrl
  6. */
  7. async function processDomainLists(domainListsUrl) {
  8. if (typeof domainListsUrl === 'string') {
  9. domainListsUrl = new URL(domainListsUrl);
  10. }
  11. /** @type Set<string> */
  12. const domainSets = new Set();
  13. /** @type string[] */
  14. const domains = (await got(domainListsUrl).text()).split('\n');
  15. domains.forEach(line => {
  16. if (
  17. line.startsWith('#')
  18. || line.startsWith('!')
  19. || line.startsWith(' ')
  20. || line === ''
  21. || line.startsWith('\r')
  22. || line.startsWith('\n')
  23. ) {
  24. return;
  25. }
  26. domainSets.add(line.trim());
  27. });
  28. return [...domainSets];
  29. }
  30. /**
  31. * @param {string | URL} hostsUrl
  32. */
  33. async function processHosts(hostsUrl, includeAllSubDomain = false) {
  34. if (typeof hostsUrl === 'string') {
  35. hostsUrl = new URL(hostsUrl);
  36. }
  37. /** @type Set<string> */
  38. const domainSets = new Set();
  39. /** @type string[] */
  40. const hosts = (await got(hostsUrl).text()).split('\n');
  41. hosts.forEach(line => {
  42. if (line.includes('#')) {
  43. return;
  44. }
  45. if (line.startsWith(' ') || line.startsWith('\r') || line.startsWith('\n') || line.trim() === '') {
  46. return;
  47. }
  48. const [, ...domains] = line.split(' ');
  49. const domain = domains.join(' ').trim();
  50. if (rDomain.test(domain)) {
  51. if (includeAllSubDomain) {
  52. domainSets.add(`.${domain}`);
  53. } else {
  54. domainSets.add(domain);
  55. }
  56. }
  57. });
  58. return [...domainSets];
  59. }
  60. /**
  61. * @param {string | URL} filterRulesUrl
  62. * @returns {Promise<{ white: Set<string>, black: Set<string> }>}
  63. */
  64. async function processFilterRules(filterRulesUrl) {
  65. if (typeof filterRulesUrl === 'string') {
  66. filterRulesUrl = new URL(filterRulesUrl);
  67. }
  68. /** @type Set<string> */
  69. const whitelistDomainSets = new Set();
  70. /** @type Set<string> */
  71. const blacklistDomainSets = new Set();
  72. /** @type string[] */
  73. const filterRules = (await got(filterRulesUrl).text()).split('\n').map(line => line.trim());
  74. filterRules.forEach(line => {
  75. if (
  76. line === ''
  77. || line.includes('#')
  78. || line.includes('!')
  79. || line.includes('*')
  80. || line.includes('/')
  81. || line.includes('$') && !line.startsWith('@@')
  82. || line.trim() === ''
  83. || isIP(line) !== 0
  84. ) {
  85. return;
  86. }
  87. if (line.startsWith('@@||')
  88. && (
  89. line.endsWith('^')
  90. || line.endsWith('^|')
  91. || line.endsWith('^$badfilter')
  92. || line.endsWith('^$1p')
  93. )
  94. ) {
  95. const domain = line
  96. .replaceAll('@@||', '')
  97. .replaceAll('^$badfilter', '')
  98. .replaceAll('^$1p', '')
  99. .replaceAll('^|', '')
  100. .replaceAll('^', '')
  101. .trim();
  102. if (rDomain.test(domain)) {
  103. whitelistDomainSets.add(domain);
  104. }
  105. } else if (
  106. line.startsWith('||')
  107. && (
  108. line.endsWith('^')
  109. || line.endsWith('^|')
  110. || line.endsWith('^$all')
  111. )
  112. ) {
  113. const domain = line
  114. .replaceAll('||', '')
  115. .replaceAll('^|', '')
  116. .replaceAll('^$all', '')
  117. .replaceAll('^', '')
  118. .trim();
  119. if (rDomain.test(domain)) {
  120. blacklistDomainSets.add(`.${domain}`);
  121. }
  122. } else if (line.startsWith('://')
  123. && (
  124. line.endsWith('^')
  125. || line.endsWith('^|')
  126. )
  127. ) {
  128. const domain = `${line.replaceAll('://', '').replaceAll('^|', '').replaceAll('^', '')}`.trim();
  129. if (rDomain.test(domain)) {
  130. blacklistDomainSets.add(domain);
  131. }
  132. }
  133. });
  134. return {
  135. white: whitelistDomainSets,
  136. black: blacklistDomainSets
  137. };
  138. }
  139. module.exports.processDomainLists = processDomainLists;
  140. module.exports.processHosts = processHosts;
  141. module.exports.processFilterRules = processFilterRules;