إعادة كتابة المحتوى
يستطيع Chute البحث والاستبدال في محتوى طلبات واستجابات HTTP باستخدام تعبيرات نمطية أو تعبيرات JSONPath. هذا يتطلب فك تشفير MitM لحركة HTTPS.
ملاحظة: لا يُعالَج طلب HTTP العادي إلا حين يصل إلى Chute عبر بروكسي HTTP الخاص به؛ أما HTTP العادي الذي يصل عبر واجهة TUN فيُمرَّر دون أي تعديل. ويرسل Chute Android كل الحركة عبر TUN ما لم يُفعَّل بروكسي HTTP للنظام (System HTTP Proxy) في الإعدادات (Settings)، الذي يسلّم التطبيقات بروكسي HTTP الخاص بـ Chute (على Android 10 وما بعده؛ وهو معطّل افتراضياً).
برنامجا jq في Surge، http-request-jq وhttp-response-jq، مدعومان أيضاً — راجع صيغة Surge.
تُعرف قواعد إعادة كتابة المحتوى في القسم [Body Rewrite]. لكل اتجاه (request / response)، تُطبق فقط أول قاعدة مطابقة على الرسالة. وإذا طابق الرسالةَ نفسها سكريبت http-request أو http-response يتلقى المحتوى، طُبّقت القاعدة أولاً ورأى السكريبت المحتوى بعد إعادة كتابته؛ ويعمل سكريبت http-request-before-send بعدهما كليهما.
[Body Rewrite]
^https://api\.example\.com/response.* response regex "old-text" "new-text"
^https://api\.example\.com/request.* request regex "sensitive" "[redacted]"
^https://api\.example\.com/data.* jsonpath-response jsonpath $.ads null
تنسيق القاعدة
كل قاعدة تتبع هذا التنسيق العام:
<URL regex> [direction] <mode> <pattern> <replacement>
ملاحظة: يُطابَق التعبير النمطي للرابط في أي موضع من رابط الطلب الكامل، وفي مساره وحده أيضاً، كما في إعادة كتابة الرابط:
^https://example\.comيغطي بالفعل كل مسار وسلسلة استعلام على ذلك المضيف، لذا لا حاجة إلى.*في النهاية، و^/apiيطابق كل طلب يبدأ مساره بـ/api. ويبدأ الرابط الكامل للطلب المفكوك تشفيره بـhttps://، لذا لا يطابقه نمط^http://أبداً. يحتفظ النمط بحالة أحرفه، فتبقى\Sو\Dو\Wو\Bعلى معناها؛ أما المطابقة نفسها فلا تميّز بين الأحرف الكبيرة والصغيرة.
يفتح # أو // في بداية السطر أو بعد مسافة تعليقاً يمتد حتى نهاية السطر، ما لم يكن داخل علامتي اقتباس مزدوجتين؛ أما ; فلا يفتح تعليقاً أبداً. راجع التعليقات.
صيغة Surge
تُقبل أيضاً صيغة السطر الخاصة بـ Surge: يأتي الاتجاه أولاً، وتُحذف الكلمة المفتاحية regex.
[Body Rewrite]
http-response ^https://api\.example\.com/feed "\"ads\":\s*\[.*?\]" "\"ads\":[]"
http-request ^https://api\.example\.com/submit "sensitive" "[redacted]"
قد يحمل سطر Surge عدة أزواج نمط/استبدال، وتُطبَّق من اليسار إلى اليمين، كل زوج على ناتج سابقه. يأخذ http-request-jq وhttp-response-jq برنامج jq بدلاً من نمط واستبدال: <type> <URL pattern> <jq program>، ويُوضع البرنامج عادةً بين علامتَي اقتباس لأنه يحتوي على مسافات. وخارج علامتَي الاقتباس، يبدأ // أو # المسبوق بمسافة تعليقاً ينهي البرنامج عنده؛ أما داخلهما فـ // هو عامل البديل في jq، لذا ضع البرنامج الذي يستخدمه بين علامتَي اقتباس. يُطبَّق على المحتوى بوصفه JSON. المحتوى الذي ليس JSON، والبرنامج الذي يرفع خطأ، والبرنامج الذي لا ينتج مخرجات: تترك الحالات الثلاث المحتوى كما هو؛ أما البرنامج غير الصالح فيُبلَّغ عنه وتُتخطّى تلك القاعدة وحدها دون إفشال بقية الملف. لا يستطيع البرنامج قراءة الملفات ولا البيئة: import وinclude لا يجدان شيئاً، و$ENV وenv فارغان.
ملاحظة: يشغّل Chute Android برامج jq على jackson-jq. ومخرجاته محدودة بـ 4096 نتيجة أو 4 ميغابايت — والبرنامج الذي ينتج أكثر من ذلك يترك المحتوى كما هو — كما تنقصه بعض الدوال المدمجة في jq 1.7، ومنها دوال التاريخ عدا
nowوtodateiso8601وfromdateiso8601(strftimeوstrptimeوmktimeوgmtimeوtodateوما شابهها)، و@base32و@base32d، وabsوtoarray، وtrimوltrimوrtrim، وINوINDEXوJOIN، وtostreamوfromstream. والبرنامج الذي يستدعي إحداها يرفع خطأ حين يعمل، فيبقى المحتوى كما هو.
الاتجاه
| الكلمة المفتاحية | الوصف |
|---|---|
response |
تطبيق على محتوى الاستجابة (الافتراضي إذا تم حذفه) |
request |
تطبيق على محتوى الطلب |
الأنماط
| النمط | الوصف |
|---|---|
regex |
بحث واستبدال بتعبير نمطي |
jsonpath-response / jsonpath-request / body-jsonpath-response / body-jsonpath-request |
تعديل قائم على JSONPath |
نمط Regex
يقوم ببحث واستبدال نمطي قياسي على نص المحتوى المفكوك. يستخدم NSRegularExpression (ICU) بمطابقة غير حساسة لحالة الأحرف. يدعم الاستبدال مراجع مجموعات الالتقاط ($1، $2، إلخ).
<URL regex> [response|request] regex <pattern> <replacement>
مثال — إزالة الإعلانات من استجابة JSON:
[Body Rewrite]
^https://api\.example\.com/feed.* response regex "\"ads\":\s*\[.*?\]" "\"ads\":[]"
مثال — تنقية محتوى الطلب:
[Body Rewrite]
^https://api\.example\.com/submit.* request regex "\"password\":\s*\".*?\"" "\"password\":\"[FILTERED]\""
مثال — استخدام مجموعات الالتقاط لإعادة تنسيق البيانات:
[Body Rewrite]
// تبديل "last, first" إلى "first last"
^https://api\.example\.com/users.* response regex "\"name\":\s*\"(\w+),\s*(\w+)\"" "\"name\":\"$2 $1\""
مثال — إعادة كتابة الروابط المضمنة في محتوى الاستجابة:
[Body Rewrite]
^https://api\.example\.com.* response regex "https://old-cdn\.example\.com" "https://new-cdn.example.com"
الرموز التي تحتوي على مسافات يجب وضعها بين علامتي اقتباس مزدوجتين:
[Body Rewrite]
^https://example\.com.* response regex "old value with spaces" "new value"
لتضمين علامة اقتباس مزدوجة حرفية داخل رمز مقتبس، قم بتهريبها بشرطة مائلة للخلف: \".
نمط JSONPath
يعدل محتويات JSON باستخدام تعبيرات JSONPath. يدعم قراءة، تعيين، وحذف القيم في مسارات محددة.
<URL regex> jsonpath-response|jsonpath-request jsonpath <jsonpath-expression> [value]
صيغة JSONPath المدعومة
| التعبير | الوصف |
|---|---|
$.key |
الوصول إلى خاصية كائن |
$.key.subkey |
الوصول إلى خصائص متداخلة |
$[0] |
الوصول إلى عنصر مصفوفة بالفهرس |
$.key[0].subkey |
وصول مختلط للكائنات والمصفوفات |
$.items[*].name |
أحرف البدل: جميع العناصر في المصفوفة |
$.*.value |
أحرف البدل: جميع الخصائص |
يأخذ .* كل عضو في الكائن وكل عنصر في المصفوفة، لذا يصل $.items.*.name إلى اسم كل عنصر. وحين يكون الخطوة الأخيرة على مصفوفة لا يغيّر شيئاً؛ ولاستبدال العناصر نفسها استخدم [*].
أنواع القيم
| القيمة | النتيجة |
|---|---|
string |
تعيين إلى قيمة نصية — كل ما ليس أحد الأشكال أدناه، فتبقى example.com و 1.0.0-beta و 12abc نصوصاً |
42 |
تعيين إلى عدد صحيح — رمز هو بتمامه عدد JSON بلا جزء كسري ولا أُس |
3.14 |
تعيين إلى عدد عشري — عدد JSON بجزء كسري أو بأُس، مثل 1e3، أو عدد صحيح أكبر من أن تسعه 64 بت |
true |
تعيين إلى قيمة منطقية true |
false |
تعيين إلى قيمة منطقية false |
[…] أو {…} |
بلا علامات اقتباس: تُحلَّل كـ JSON وتُعيَّن مصفوفةً أو كائناً؛ وهي الحقل الأخير، فبقية السطر تُؤخذ كما كُتبت وقد تحوي مسافات. أما مع علامات الاقتباس، أو إن لم تكن JSON صالحاً، فتبقى نصاً. |
null أو nil أو محذوف |
حذف المسار |
ملاحظة: وضع القيمة بين علامتي اقتباس لا يفرض النوع النصي — تُزال علامات الاقتباس أثناء التقطيع ويُستنتج النوع من المحتوى المتبقي، لذا تصبح
"42"العدد 42 وتصبح"true"القيمة المنطقية true وتحذف"null"المسار؛ ولا يؤثر الاقتباس إلا في[…]و{…}، إذ تبقيان نصاً حين تُقتبسان. وتُطابَق الكلمات المفتاحية حرفياً بما في ذلك حالة الأحرف، فتكونTrueوNULLنصوصاً. ولا يُعدّ الرمز عدداً إلا إذا كان بتمامه عدداً مكتوباً كما يكتبه JSON: فتبقى+1و.5و1.و007نصوصاً، وكذلك العدد الأكبر من أن يسعه عدد عشري، مثل1e400. ولا توجد صيغة تعيّن نصاً مثل"42"أو"true"— استخدم لذلك قاعدةregexبدلاً منها.
مثال — تعيين حقل JSON:
[Body Rewrite]
^https://api\.example\.com/profile.* jsonpath-response jsonpath $.user.name "Anonymous"
مثال — حذف حقل JSON:
[Body Rewrite]
^https://api\.example\.com/data.* jsonpath-response jsonpath $.tracking null
مثال — تعديل بأحرف البدل:
[Body Rewrite]
^https://api\.example\.com/list.* jsonpath-response jsonpath $.items[*].hidden true
أمثلة عملية
إزالة معاملات التتبع من استجابات JSON
إزالة حقل trackingId من جميع استجابات API. بما أن أول قاعدة مطابقة فقط تُطبق لكل اتجاه، استخدم قاعدة واحدة لكل نمط رابط:
[Body Rewrite]
^https://api\.example\.com/.* jsonpath-response jsonpath $.trackingId null
حقن وسم سكريبت في استجابات HTML
إلحاق وسم <script> مخصص قبل </body> في جميع صفحات HTML:
[Body Rewrite]
^https://www\.example\.com/.* response regex "</body>" "<script>console.log('injected')</script></body>"
إخفاء الحقول الحساسة في سجلات الطلبات
استبدال مفاتيح API والرموز في محتويات الطلبات الصادرة قبل وصولها إلى الخادم. بما أن أول قاعدة مطابقة فقط تُطبق لكل اتجاه، ادمج كلا الحقلين في قاعدة واحدة:
[Body Rewrite]
^https://api\.example\.com/.* request regex "\"(apiKey|token)\":\s*\"[^\"]+\"" "\"$1\":\"[REDACTED]\""
توحيد تنسيقات التواريخ في الاستجابات
استبدال تواريخ ISO بتنسيق أقصر:
[Body Rewrite]
^https://api\.example\.com/.* response regex "(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z" "$1/$2/$3 $4:$5"
تعطيل أعلام الميزات في إعدادات التطبيق
فرض جميع أعلام الميزات إلى false في نقطة نهاية إعدادات:
[Body Rewrite]
^https://api\.example\.com/config.* jsonpath-response jsonpath $.features[*].enabled false
إعادة كتابة روابط CDN في الاستجابات المخزنة مؤقتاً
استبدال جميع الإشارات إلى CDN قديم بآخر جديد:
[Body Rewrite]
^https://www\.example\.com/.* response regex "https://old-cdn\.example\.com" "https://new-cdn.example.com"
مراحل المعالجة
إعادة كتابة المحتوى تتعامل تلقائياً مع:
- Content-Encoding: يدعم
gzipوdeflate. يتخطى الترميزات غير المدعومة. - Transfer-Encoding: يفك ترميز chunked transfer encoding قبل المعالجة.
- فك الترميز: يفك ضغط المحتويات قبل تطبيق قواعد إعادة الكتابة.
- إعادة الترميز: يعيد ضغط المحتويات ويحدث
Content-Length. يزيل ترويسةTransfer-Encoding. - Accept-Encoding: عندما تطابق قاعدة استجابة رابط أحد الطلبات، تُعاد كتابة ترويسة
Accept-Encodingللطلب إلىgzip, deflate, identityبحيث تبقى الاستجابة بترميز قابل للفك.
الحد الأقصى لحجم المحتوى لمعالجة إعادة الكتابة هو 128KB في HTTP/1.x (HTTP العادي وHTTP/1.1 المفكوك تشفيره)؛ والمحتويات الأكبر تمر دون تعديل. أما رسالة HTTP/2 المفكوك تشفيرها فتُخزَّن كاملة وتُعاد كتابتها مهما كان حجمها.
في HTTP/1.x لا يُعاد كتابة محتوى الاستجابة إلا بعد وصوله كاملاً. فإذا أغلق الخادم الاتصال قبل ذلك، فالمحتوى الذي لا يحمل
Content-Lengthولا ترميز chunked ينتهي بانتهاء الاتصال، فيكون كاملاً ويُعاد كتابته كالمعتاد. أما المحتوى المؤطَّر بـContent-Lengthأو بترميز chunked الذي قطعه الإغلاق فيُرسَل إلى العميل كما وصل تماماً، دون إعادة كتابة ودون تغييرContent-Length، ثم يُغلَق الاتصال، ليتبيّن العميل أن الاستجابة ناقصة.
ملاحظات
- لحركة HTTPS، يجب تفعيل فك تشفير MitM لاسم المضيف المطابق.
- مطابقة Regex غير حساسة لحالة الأحرف. قالب الاستبدال يدعم مراجع مجموعات الالتقاط ICU:
$0(المطابقة الكاملة)،$1(المجموعة الأولى)،$2(المجموعة الثانية)، إلخ. - نمط الرابط أو نمط المحتوى الذي ليس تعبيراً نمطياً صالحاً يجعل سطر regex أو JSONPath خطأً في الإعدادات، ولا تُحمَّل القاعدة؛ أما سطر jq فيُتخطّى مع تحذير بدلاً من ذلك. وفي الأزواج التي تلي الزوج الأول، لا يُسقط النمط غير الصالح إلا ذلك الزوج، مع تحذير في السجل.
- نمط JSONPath يطبق فقط إذا كان المحتوى JSON صالحاً.
- قواعد إعادة كتابة المحتوى تطبق على نص المحتوى المفكوك (UTF-8).
- تُطبق فقط أول قاعدة مطابقة لكل اتجاه (request / response) على الرسالة. عرّف قاعدة واحدة مجمّعة إذا كنت بحاجة إلى عدة تعديلات.
- حذف مسار JSONPath غير موجود يترك المحتوى دون تغيير. تعيين قيمة ينشئ المفتاح عندما يكون الكائن الأب موجوداً؛ أما إذا كان مسار وسيط مفقوداً، فلا يحدث شيء.
هذه الصفحة ترجمة للنسخة الإنجليزية. في حال وجود اختلاف، يُعتمد على النسخة الإنجليزية.
ملاحظة: التطبيق لا يدعم اللغة العربية حاليًا.