JavaScript-скриптинг

Chute поддерживает JavaScript-скриптинг для расширенной модификации запросов/ответов, пользовательского сопоставления правил, разрешения DNS и запланированных задач. Скрипты используют движок JavaScriptCore от Apple и следуют Surge-совместимому API скриптов.

Скрипты определяются в разделе [Script] файла конфигурации.

Конфигурация

[Script]
MyScript = type=http-request, script-path=/path/to/script.js, pattern=^https?://example\.com, requires-body=true, max-size=262144, timeout=10, argument=myArg, debug=true
CronJob = type=cron, script-path=/path/to/cron.js, cron-expression=* * * * *, wake-system=true

Параметры скриптов

Параметр Обязательно По умолчанию Описание
type Да http-request Тип триггера скрипта (см. ниже)
script-path Да Локальный путь к файлу или HTTP(S) URL к JS-скрипту
pattern Нет (совпадает со всем) Регулярное выражение URL для фильтрации запуска скрипта
requires-body Нет автоопределение Принудительно передавать скрипту полное тело запроса/ответа
max-size Нет 131072 (128 КБ) Максимальный размер тела в байтах для скриптов с доступом к телу
timeout Нет 5.0 секунд Тайм-аут выполнения одного скрипта
argument Нет Пользовательский строковый аргумент, доступный как $argument в JS
debug Нет false Пропустить кэш компиляции для отладки
cron-expression Нет Выражение расписания cron (только для типа cron)
wake-system Нет false Пробуждать систему для выполнения cron-скриптов (только iOS)
enable Нет true Включить или отключить этот скрипт
script-update-interval Нет 0 Секунды между обновлениями удаленных скриптов (-1 = никогда, 0 = только при запуске)

Типы скриптов

Строка типа Enum Описание
http-request HTTP Request Перехват и изменение HTTP-запросов до отправки
http-response HTTP Response Перехват и изменение HTTP-ответов до клиента
http-request-before-send HTTP Request Before Send Изменение запроса после сбора полного тела, перед отправкой
rule Rule Пользовательская логика сопоставления правил
dns DNS Пользовательское разрешение DNS
cron Cron Запланированные/периодические скрипты
event Event Обработчики системных событий (например, network-changed)

Автоопределение тела: Если исходный код скрипта содержит $request.body или $response.body, тело будет автоматически предоставлено до max-size. Используйте requires-body=true для принудительного включения этого поведения.


Справочник JavaScript API

Скрипты выполняются в изолированной среде JavaScriptCore со следующими доступными глобальными объектами.

$request (Только чтение)

Доступно в: http-request, http-response, http-request-before-send, rule

Свойство Тип Описание
.url String Полный URL запроса
.method String HTTP-метод (GET, POST и др.) или QUERY для DNS
.headers Object Заголовки запроса как пары ключ-значение
.body String или null Тело запроса (в кодировке UTF-8)
.hostname String Целевое имя хоста
.destPort Number Порт назначения
.processPath String Путь запрашивающего процесса (только macOS)
.userAgent String Значение заголовка User-Agent
.sourceIP String Исходный IP-адрес
.listenPort Number Порт прослушивания прокси
.requestId String Уникальный идентификатор запроса
.dnsResult String Разрешенный IP-адрес
.srcPort Number Исходный порт
.protocol String Определенный протокол: http, https, tcp, dns

$response (Только чтение)

Доступно в: http-response

Свойство Тип Описание
.status Number Код статуса HTTP
.headers Object Заголовки ответа как пары ключ-значение
.body String или null Тело ответа (в кодировке UTF-8)

$done(value) — Обработчик завершения

Должен быть вызван ровно один раз в конце скрипта для сигнализации о завершении. Выполнение скрипта блокируется до вызова $done() или истечения тайм-аута.

$done({})                        // Пропуск — без изменений
$done()                          // Прервать соединение
$done({matched: true})           // Результат сопоставления правила (только для rule-скриптов)
$done({address: "1.2.3.4"})      // Результат DNS (только для dns-скриптов)

Возвращаемые значения скрипта HTTP Request:

$done({
    url: "https://new.example.com/path",     // Перезаписать URL
    headers: {"X-Custom": "value"},           // Изменить заголовки
    body: "new request body",                 // Изменить тело
    response: {                               // Вернуть синтетический ответ (пропустить отправку)
        status: 200,
        headers: {"Content-Type": "text/html"},
        body: "<html>Blocked</html>"
    }
})

Когда указан response, запрос замыкается: Chute возвращает синтетический ответ напрямую клиенту, не обращаясь к исходному серверу. Это полезно для блокировки, имитации API или возврата кэшированного контента.

Возвращаемые значения скрипта HTTP Response:

$done({
    status: 200,                              // Изменить код статуса
    headers: {"X-Custom": "value"},           // Изменить заголовки ответа
    body: "new response body",                // Изменить тело ответа
    url: "https://other.example.com"          // Вызвать 302 редирект
})

Когда указан url, Chute возвращает 302 редирект на указанный URL вместо исходного ответа.

Возвращаемые значения скрипта DNS:

$done({address: "1.2.3.4"})                  // Один IP
$done({addresses: ["1.2.3.4", "5.6.7.8"]})   // Несколько IP
$done({address: "10.0.0.1", ttl: 300})       // С пользовательским TTL (секунды, по умолчанию 60)
$done({server: "8.8.8.8"})                   // Переслать на конкретный DNS-сервер

$httpClient — Асинхронный HTTP-клиент

Выполнение HTTP-запросов из скриптов. Все запросы отменяются при вызове $done() или по тайм-ауту.

$httpClient.get(url, function(error, response, data) {
    if (error) {
        console.log("Request failed: " + error)
    } else {
        console.log("Status: " + response.status)
        console.log("Response: " + data)
    }
})

$httpClient.post(url, {headers: {...}, body: "...", timeout: 5}, callback)
$httpClient.put(url, options, callback)
$httpClient.del(url, options, callback)
$httpClient.head(url, options, callback)
$httpClient.options(url, options, callback)
$httpClient.patch(url, options, callback)

Сигнатура колбэка: callback(error, response, data)

  • error: Строка ошибки или null
  • response: {status: Number, headers: Object} или null
  • data: Строка тела ответа в UTF-8 или null

$persistentStore — Хранилище ключ-значение

Постоянное хранилище ключ-значение, сохраняющееся между перезапусками скриптов и процессов. Основано на NSUserDefaults.

$persistentStore.write(data, key)   // Сохранить значение
$persistentStore.read(key)          // Получить значение
$persistentStore.remove(key)        // Удалить значение

$notification — Локальные уведомления

Отправка локальных системных уведомлений.

$notification.post("Title", "Subtitle", "Notification body text")

$network — Информация о сети

Информация о состоянии сети (только чтение).

$network.dns   // Массив IP-адресов DNS-серверов
$network.wifi  // {ssid: "WiFiName", bssid: "aa:bb:cc:dd:ee:ff"}

$environment — Информация о среде выполнения

$environment.system     // "iOS" или "macOS"
$environment.appVersion // Строка версии приложения

$utils — Утилиты

$utils.geoip("1.2.3.4")   // Код страны (например, "US")
$utils.ipasn("1.2.3.4")   // Номер ASN (например, "13335")
$utils.ungzip(data)       // Распаковать данные gzip

$klne — API управления прокси

Управление прокси во время выполнения из скриптов.

$klne.policyGroups                    // Получить все группы политик
$klne.selectPolicy("Group", "Proxy")  // Переключить политику для группы
$klne.getActiveConnections()          // Список активных соединений
$klne.closeConnection("id")           // Закрыть соединение
$klne.flushDNS()                      // Очистить кэш DNS
$klne.startURLTest("Group")           // Запустить тест URL для группы
$klne.reloadConfiguration()           // Перезагрузить всю конфигурацию
$klne.setOutboundMode("rule")         // Установить режим: "global", "proxy", "direct", "rule"
$klne.setHTTPCaptureEnabled(true)     // Включить/отключить MITM

$script — Метаданные скрипта

$script.name       // Имя скрипта из конфигурации
$script.type       // Строка типа скрипта
$script.startTime  // Временная метка epoch

Глобальные переменные на выполнение

Следующие переменные внедряются при каждом выполнении скрипта и специфичны для определенных типов скриптов.

$argument — Аргумент скрипта

Строковое значение из параметра argument= в конфигурации скрипта. Доступно в: http-request, http-response, http-request-before-send, rule, dns, cron.

console.log("Argument: " + $argument)

$domain — Домен DNS (только DNS-скрипты)

Запрашиваемое доменное имя. Доступно только в dns скриптах.

var domain = $domain  // например, "example.com"

$cronexp — Выражение Cron (только Cron-скрипты)

Выражение расписания cron из конфигурации скрипта. Доступно только в cron скриптах.

console.log("Schedule: " + $cronexp)  // например, "*/30 * * * *"

$event — Информация о событии (только Event-скрипты)

Информация о вызвавшем событии. В настоящее время поддерживается только network-changed.

console.log("Event: " + $event.name)  // "network-changed"

console — Логирование

console.log("Debug message")    // Подробный журнал
console.warn("Warning message")  // Предупреждение
console.error("Error message")   // Ошибка с префиксом [JS-ERROR]

setTimeout(fn, seconds) — Таймер

Планирование выполнения функции с задержкой.

setTimeout(function() {
    console.log("Delayed execution")
}, 2.5)  // 2.5 секунды

$script(subScriptPath) — Загрузчик подскриптов

Загрузка и выполнение другого файла JavaScript.

$script("/path/to/helper.js")
$script("https://example.com/remote-script.js")

// Передача данных между скриптами с использованием $persistentStore

Подробности типов скриптов

Скрипт HTTP Request

Выполняется при получении заголовков запроса. Может изменять URL, заголовки и тело до отправки запроса.

[Script]
ModifyHeaders = type=http-request, script-path=modify.js, pattern=^https://api\.example\.com

Скрипт HTTP Response

Выполняется при получении заголовков ответа. Может изменять статус, заголовки и тело до возврата клиенту.

[Script]
ModifyResponse = type=http-response, script-path=response.js, pattern=^https://api\.example\.com

Скрипт HTTP Request Before Send

Выполняется после сбора полного тела запроса, непосредственно перед отправкой. Полезно для изменения тел POST/PUT запросов.

[Script]
BeforeSend = type=http-request-before-send, script-path=before-send.js, pattern=^https://api\.example\.com, requires-body=true

Скрипт Rule

Пользовательское сопоставление правил. Скрипт должен вызвать $done({matched: true}) или $done({matched: false}).

[Rule]
SCRIPT,MyRuleScript,DIRECT

[Script]
MyRuleScript = type=rule, script-path=rule.js

Скрипт DNS

Пользовательское разрешение DNS. Получает $domain и возвращает разрешенный(е) адрес(а).

// dns.js
var domain = $domain
if (domain === "internal.example.com") {
    $done({address: "10.0.0.1", ttl: 300})
} else {
    $done({})  // Пропуск к обычному разрешению DNS
}

Скрипт Cron

Запланированное выполнение с использованием выражений cron. Минимальный интервал — 60 секунд.

[Script]
HourlyTask = type=cron, script-path=hourly.js, cron-expression=0 * * * *

Поддерживается упрощенный синтаксис cron (например, */30 * * * * для каждых 30 минут, значения, разделенные запятыми).

Скрипт Event

Запускается системными событиями. В настоящее время поддерживает событие network-changed (срабатывает при смене Wi-Fi или сотовой сети).

[Script]
NetChange = type=event, script-path=network-changed.js

Объект $event доступен:

$event.name  // "network-changed"

Практические примеры

Перенаправление мобильных устройств

Скрипт http-request, который перенаправляет мобильных пользователей на основе User-Agent:

[Script]
MobileRedirect = type=http-request, script-path=mobile-redirect.js, pattern=^https://example\.com
// mobile-redirect.js
var ua = $request.headers["User-Agent"] || ""
if (/Mobile|Android|iPhone/.test(ua)) {
    $done({
        response: {
            status: 302,
            headers: {"Location": "https://m.example.com" + $request.url.replace(/.*example\.com/, "")},
            body: ""
        }
    })
} else {
    $done({})
}

Блокировка контента в API-ответах

Скрипт http-response, который удаляет рекламу и спонсируемый контент из JSON-ответа API:

[Script]
RemoveAds = type=http-response, script-path=remove-ads.js, pattern=^https://api\.example\.com/feed, requires-body=true
// remove-ads.js
var body = JSON.parse($response.body)
if (body.ads) {
    delete body.ads
}
if (body.recommendations) {
    body.recommendations = body.recommendations.filter(function(r) {
        return !r.sponsored
    })
}
$done({body: JSON.stringify(body)})

Изменение тела запроса перед отправкой

Скрипт http-request-before-send, который очищает POST-данные:

[Script]
SanitizePayload = type=http-request-before-send, script-path=sanitize.js, pattern=^https://api\.example\.com/submit, requires-body=true
// sanitize.js
var body = JSON.parse($request.body)
body.clientSecret = "[REDACTED]"
body.timestamp = Math.floor(Date.now() / 1000)
$done({body: JSON.stringify(body)})

Пользовательское правило: маршрутизация по времени

Скрипт rule, который выбирает разный прокси в зависимости от времени суток:

[Rule]
SCRIPT,TimeBasedRule,ProxyA

[Script]
TimeBasedRule = type=rule, script-path=time-rule.js
// time-rule.js
var hour = new Date().getHours()
if (hour >= 9 && hour < 18) {
    $done({matched: false})  // Переход к следующему правилу в рабочее время
} else {
    $done({matched: true})   // Использовать ProxyA в нерабочее время
}

Пользовательский DNS для внутренних доменов

Скрипт dns, который разрешает внутренние имена хостов в локальные IP:

[Script]
InternalDNS = type=dns, script-path=internal-dns.js
// internal-dns.js
var internalHosts = {
    "gitlab.local": "10.0.0.10",
    "registry.local": "10.0.0.11",
    "monitor.local": "10.0.0.12"
}
if (internalHosts[$domain]) {
    $done({address: internalHosts[$domain], ttl: 3600})
} else {
    $done({})  // Пропуск к обычному DNS
}

Автоматическое переключение политики при смене сети

Скрипт event, который переключается на консервативную группу политик при сотовой связи:

[Script]
NetSwitch = type=event, script-path=network-switch.js
// network-switch.js
if (!$network.wifi.ssid) {
    // На сотовой связи — использовать группу с низким трафиком
    $klne.selectPolicy("MainGroup", "LowDataProxy")
    console.log("Switched to cellular profile")
} else if ($network.wifi.ssid === "Office") {
    $klne.selectPolicy("MainGroup", "DIRECT")
    console.log("Switched to office profile")
}

Периодическая проверка здоровья

Скрипт cron, который проверяет здоровье прокси каждые 30 минут:

[Script]
HealthCheck = type=cron, script-path=health-check.js, cron-expression=*/30 * * * *
// health-check.js
$httpClient.head("https://www.google.com/generate_204", {timeout: 10},
    function(error, response, data) {
        if (error || response.status !== 204) {
            console.error("Health check failed: " + (error || "status " + response.status))
            $notification.post("Chute Alert", "Health Check", "Cannot reach Google")
        } else {
            console.log("Health check OK")
        }
    }
)
$done()

Обогащение API-ответов внешними данными

Скрипт http-response, который обогащает пользовательские данные, вызывая вторичный API:

[Script]
EnrichUsers = type=http-response, script-path=enrich.js, pattern=^https://api\.example\.com/users, requires-body=true
// enrich.js
var users = JSON.parse($response.body)
var pending = users.length
if (pending === 0) { $done({}) }

users.forEach(function(user, index) {
    $httpClient.get("https://internal-api.example.com/avatar/" + user.id,
        function(error, resp, data) {
            if (!error && resp.status === 200) {
                users[index].avatar = JSON.parse(data).url
            }
            pending--
            if (pending === 0) {
                $done({body: JSON.stringify(users)})
            }
        }
    )
})

Модель выполнения

  • Все скрипты выполняются на выделенной последовательной очереди для потокобезопасности.
  • Каждое выполнение скрипта имеет свой тайм-аут; если $done() не вызван в течение тайм-аута, скрипт обрабатывается как пропуск.
  • Пул JSContext (размер 3) используется для производительности; контексты переиспользуются между выполнениями.
  • Компиляция скриптов кэшируется по умолчанию; используйте debug=true для обхода кэша.
  • На iOS/tvOS скрипты ограничены лимитом памяти 10 МБ; на macOS — 512 МБ.
  • Удаленные скрипты (пути HTTP/HTTPS) загружаются при запуске и опционально перезагружаются каждые script-update-interval секунд.

Интеграция модульных скриптов

Скрипты также могут быть определены в файлах Module (.sgmodule) в разделе [Script]. ```

S. Smart Rabbit LLC © All Rights Reserved            updated 2026-06-28 02:09:17

results matching ""

    No results matching ""