fingerprintjs

Форк
0
109 строк · 2.9 Кб
1
import * as fs from 'fs'
2
import * as readline from 'readline'
3
import { spawn, SpawnOptions } from 'child_process'
4
import { URL } from 'url'
5
import got from 'got'
6

7
export async function eachLineInFile(
8
  filePath: string,
9
  callback: (line: string) => void | Promise<void>,
10
): Promise<void> {
11
  const fileStream = fs.createReadStream(filePath)
12

13
  try {
14
    const reader = readline.createInterface({
15
      input: fileStream,
16
      crlfDelay: Infinity,
17
    })
18
    const iterator = reader[Symbol.asyncIterator]()
19

20
    for (;;) {
21
      const value = await iterator.next()
22
      if (value.done) {
23
        break
24
      }
25

26
      await callback(value.value)
27
    }
28
  } finally {
29
    fileStream.destroy()
30
  }
31
}
32

33
export async function fetchFilter(
34
  url: string,
35
  abort?: Promise<unknown>,
36
  forceTreatAsFilter = false,
37
): Promise<string[]> {
38
  const request = got(url, {
39
    headers: {
40
      'User-Agent':
41
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) ' +
42
        'Chrome/91.0.4472.114 Safari/537.36',
43
    },
44
  })
45

46
  abort?.catch(() => undefined).then(() => request.cancel())
47

48
  const response = await request.catch((error) => {
49
    if (request.isCanceled) {
50
      // Never resolve the promise of the function when it's aborted
51
      return new Promise<never>(() => undefined)
52
    }
53
    throw error
54
  })
55

56
  if (response.statusCode >= 300) {
57
    throw new Error(`HTTP status ${response.statusCode} (${response.statusMessage})`)
58
  }
59

60
  if (
61
    !forceTreatAsFilter &&
62
    !/^( *\[Adblock Plus.*] *(\r\n|\r|\n))?( *! *[a-z].*(\r\n|\r|\n)){2}/im.test(response.body)
63
  ) {
64
    throw new Error("The response doesn't look like a filter")
65
  }
66

67
  const filterLines = response.body.split(/(\r\n|\r|\n)/) // AdGuard filters use \r sometimes
68
  const subFilterURLs: string[] = []
69

70
  for (const line of filterLines) {
71
    const match = /^!#include +(.*?) *$/.exec(line)
72
    if (match) {
73
      // See https://stackoverflow.com/a/45801884/1118709
74
      const subFilterURL = new URL(match[1], url).href
75
      subFilterURLs.push(subFilterURL)
76
    }
77
  }
78

79
  await Promise.all(
80
    subFilterURLs.map(async (subFilterURL) => {
81
      let subFilterLines: string[]
82
      try {
83
        // We expect no recursion in actual filters
84
        subFilterLines = await fetchFilter(subFilterURL, abort, true)
85
      } catch (error) {
86
        throw new Error(`Failed to fetch a sub-filter (${subFilterURL}): ${error}`)
87
      }
88
      filterLines.push(...subFilterLines)
89
    }),
90
  )
91

92
  return filterLines
93
}
94

95
export function runCommand(command: string, options: SpawnOptions = {}): Promise<void> {
96
  return new Promise<void>((resolve, reject) => {
97
    const child = spawn(command, [], { shell: true, ...options })
98
    child.stdout?.pipe(process.stdout)
99
    child.stderr?.pipe(process.stderr)
100
    child.on('error', reject)
101
    child.on('close', (code) => {
102
      if (code) {
103
        reject(new Error(`The ${command} command has exited with code ${code}`))
104
      } else {
105
        resolve()
106
      }
107
    })
108
  })
109
}
110

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.