JavaScriptスクリプト

Chuteは、高度なリクエスト/レスポンス変更、カスタムルールマッチング、DNS解決、スケジュールタスクのためのJavaScriptスクリプトをサポートしています。スクリプトはAppleのJavaScriptCoreエンジンを使用し、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 はい JSスクリプトへのローカルファイルパスまたはHTTP(S) URL
pattern いいえ (全てにマッチ) スクリプトがトリガーされるタイミングをフィルタするURL正規表現パターン
requires-body いいえ 自動検出 スクリプトに完全なリクエスト/レスポンスボディの受信を強制
max-size いいえ 131072 (128KB) ボディにアクセスするスクリプトの最大ボディサイズ(バイト)
timeout いいえ 5.0秒 スクリプトごとの実行タイムアウト
argument いいえ JS内で$argumentとして利用可能なカスタム文字列引数
debug いいえ false デバッグ用にコンパイルキャッシュをスキップ
cron-expression いいえ Cronスケジュール式(cronタイプのみ)
wake-system いいえ false cronスクリプト実行のためにシステムをスリープ解除(iOSのみ)
enable いいえ true このスクリプトを有効または無効にする
script-update-interval いいえ 0 リモートスクリプト更新間隔の秒数(-1 = 更新しない、0 = 起動時のみ)

スクリプトタイプ

タイプ文字列 列挙型 説明
http-request HTTPリクエスト アップストリーム前にHTTPリクエストをインターセプトして変更
http-response HTTPレスポンス クライアント前にHTTPレスポンスをインターセプトして変更
http-request-before-send HTTPリクエスト送信前 完全なボディ収集後、送信前にリクエストを変更
rule ルール カスタムルールマッチングロジック
dns DNS カスタムDNS解決
cron Cron スケジュール/タイマースクリプト
event イベント システムイベントハンドラ(例: network-changed)

ボディ自動検出: スクリプトソースに$request.bodyまたは$response.bodyが含まれている場合、ボディは自動的にmax-sizeまで提供されます。この動作を強制するにはrequires-body=trueを使用してください。


JavaScript APIリファレンス

スクリプトは、以下のグローバルオブジェクトが利用可能なサンドボックス化されたJavaScriptCore環境で実行されます。

$request(読み取り専用)

利用可能なタイプ: http-requesthttp-responsehttp-request-before-sendrule

プロパティ 説明
.url String 完全なリクエストURL
.method String HTTPメソッド(GETPOSTなど)またはDNSの場合はQUERY
.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 一意のリクエストID
.dnsResult String 解決されたIPアドレス
.srcPort Number 送信元ポート
.protocol String 検出されたプロトコル: httphttpstcpdns

$response(読み取り専用)

利用可能なタイプ: http-response

プロパティ 説明
.status Number HTTPステータスコード
.headers Object キーと値のペアとしてのレスポンスヘッダー
.body String または null レスポンスボディ(UTF-8デコード)

$done(value) — 完了ハンドラ

スクリプトの終了時に必ず1回だけ呼び出して完了を通知する必要があります。スクリプトの実行は$done()が呼び出されるかタイムアウトが切れるまでブロックされます。

$done({})                        // パススルー — 変更なし
$done()                          // 接続を中止
$done({matched: true})           // ルールマッチ結果(ルールスクリプトのみ)
$done({address: "1.2.3.4"})      // DNS結果(DNSスクリプトのみ)

HTTPリクエストスクリプトの戻り値:

$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レスポンススクリプトの戻り値:

$done({
    status: 200,                              // ステータスコードを変更
    headers: {"X-Custom": "value"},           // レスポンスヘッダーを変更
    body: "new response body",                // レスポンスボディを変更
    url: "https://other.example.com"          // 302リダイレクトをトリガー
})

urlが提供された場合、Chuteは元のレスポンスの代わりに指定されたURLへの302リダイレクトを返します。

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   // DNSサーバーIPの配列
$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  // エポックタイムスタンプ

実行ごとのグローバル変数

以下の変数はスクリプト実行ごとに注入され、特定のスクリプトタイプに固有です。

$argument — スクリプト引数

スクリプト設定のargument=パラメータからの文字列値。利用可能なタイプ: http-requesthttp-responsehttp-request-before-sendrulednscron

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

$domain — DNSドメイン(DNSスクリプトのみ)

クエリ対象のドメイン名。dnsスクリプトでのみ利用可能です。

var domain = $domain  // 例: "example.com"

$cronexp — Cron式(Cronスクリプトのみ)

スクリプト設定からのcronスケジュール式。cronスクリプトでのみ利用可能です。

console.log("Schedule: " + $cronexp)  // 例: "*/30 * * * *"

$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リクエストスクリプト

リクエストヘッダーを受信したときに実行されます。リクエストが転送される前にURL、ヘッダー、ボディを変更できます。

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

HTTPレスポンススクリプト

レスポンスヘッダーを受信したときに実行されます。クライアントに返す前にステータス、ヘッダー、ボディを変更できます。

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

HTTPリクエスト送信前スクリプト

完全なリクエストボディが収集された後、アップストリームに送信する直前に実行されます。POST/PUTリクエストボディの変更に便利です。

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

ルールスクリプト

カスタムルールマッチング。スクリプトは$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 * * * *、カンマ区切りの値)。

イベントスクリプト

システムイベントによってトリガーされます。現在はnetwork-changedイベント(Wi-Fiまたは携帯電話ネットワークが変更されたときに発生)をサポートしています。

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

$eventオブジェクトが利用可能です:

$event.name  // "network-changed"

実践例

モバイルデバイスのリダイレクト

User-Agentに基づいてモバイルユーザーをリダイレクトするhttp-requestスクリプト:

[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レスポンスのコンテンツをブロック

JSON APIレスポンスから広告とスポンサーコンテンツを削除するhttp-responseスクリプト:

[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)})

送信前のリクエストボディを変更

POSTペイロードをサニタイズするhttp-request-before-sendスクリプト:

[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

内部ホスト名をローカルIPに解決するdnsスクリプト:

[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")
}

定期的なヘルスチェック

30分ごとにプロキシの健全性をチェックするcronスクリプト:

[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レスポンスを強化

二次APIを呼び出してユーザーデータを強化するhttp-responseスクリプト:

[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では、スクリプトは10MBのメモリ制限の対象となります。macOSでは512MBです。
  • リモートスクリプト(HTTP/HTTPSパス)は起動時に取得され、オプションでscript-update-interval秒ごとに再取得されます。

モジュールスクリプト統合

スクリプトはモジュールファイル(.sgmodule)の[Script]セクションでも定義できます。

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

results matching ""

    No results matching ""