cli-proxy — полное руководство
Русский · English
Подробная документация: все флаги, синтаксис правил и фильтров, горячие клавиши, работа с сертификатами и системным прокси, устройство проекта.
Короткий обзор — в README.
Максимально лёгкий CLI-прокси для перехвата, просмотра и подмены HTTP/HTTPS-трафика в реальном времени. Один статический бинарник, ноль внешних зависимостей — только стандартная библиотека Go.
╭─ cli-proxy ─────────────────────────────────────── 0.0.0.0:8080 · MITM · 128 flows ─╮
│ Flows Rules Cert Log Help │
├─────────────────────────────────────────────────────────────────────────────────────┤
│╭─ flows · 128 shown / 128 captured ─────────┬───────────────────┬────────┬────────╮ │
││ # │ Time │ Method │ Host │ Path │ Status │ Size │ │
│├──────┼──────────┼────────┼─────────────────┼───────────────────┼────────┼────────┤ │
││ 1 │ 12:04:11 │ GET │ api.example.com │ /v1/users │ 200 │ 1.2K │ │
││ 2 │ 12:04:11 │ POST │ api.example.com │ /v1/orders │ 201 │ 84B │ │
││ 3 │ 12:04:12 │ GET │ cdn.example.net │ /logo.png │ 404 │ 0B │ │
│╰──────┴──────────┴────────┴─────────────────┴───────────────────┴────────┴────────╯ │
╰──[↵]open──[f]filter──[b]brk-req──[m]mock──[M]redir──[i]break──[s]save──[q]quit──────╯
Возможности
- Сниффинг в реальном времени — все HTTP-запросы и ответы, включая тела, заголовки, размеры, время ответа и статус. Поток обновляется по мере поступления.
- Прозрачный MITM для HTTPS — собственный корневой CA, листовые сертификаты
генерируются на лету под каждый хост (SAN + ECDSA P-256, срок 365 дней —
проходит ограничения Apple/Android). Поддерживается HTTP/2 (ALPN
h2). - Breakpoints — остановка запроса или ответа, правка «на лету» прямо в raw-HTTP-сообщении (метод, URL, заголовки, тело, статус) и отправка дальше.
- Подмена ответов — локальным файлом (
file=), другим адресом (redirect=— прокси сам сходит по другому адресу) или настоящим редиректом (location=). - Переписывание — заголовки запроса и ответа, статус, тело, задержка, блокировка.
- Поиск и фильтры — по URL, регулярке, методу, статусу, хосту, телу, тегам, с отрицанием, «И», «ИЛИ» и скобками.
- Читаемые тела — прокси не запрашивает у сервера brotli/zstd, поэтому ответы мобильных клиентов видны как текст, а не как hex-дамп.
- Панели запроса и ответа с табами —
headers,body,raw; запрос слева, ответ справа, любую из панелей можно свернуть. - Читаемый JSON — тела форматируются с отступами и подсветкой, длинные строки переносятся по словам, а не обрезаются.
- Сохранённые фильтры — набор постоянных фильтров, которые остаются включёнными при переключении вкладок и переживают перезапуск.
- Установка сертификата одной кнопкой —
iв разделе Cert или-install-cert; на macOS без пароля и без sudo, с симметричным удалением. - Системный прокси — одна клавиша (
sв разделе Cert) или флаг-system-proxyнаправляет трафик всей машины через cli-proxy, включая браузеры и GUI-приложения. Прежние настройки возвращаются при выходе и даже послеkill -9. - Работа с устройств — слушает
0.0.0.0, отдаёт сертификат поhttp://<ip>:8080/cert,/cert.derи/ca.mobileconfig(профиль iOS) и показывает пошаговую инструкцию по установке. - Интерфейс — скруглённые рамки и таблицы (
╭ ╮ ╰ ╯ ┬ ┴ ├ ┤ ┼), полностью клавиатурный, плюс мышь: наведение подсвечивает строки, вкладки и кнопки, клик выбирает. Пункты меню переключаются стрелками←/→(илиTab).
Установка
cli-proxy — один статический бинарник: установщика нет и удалять потом
нечего. Выбирайте привычный пакетный менеджер или просто возьмите архив и
положите программу куда удобно.
macOS и Linux
brew install sadgoodman/tap/cli-proxy
Windows
Scoop не требует прав администратора:
scoop bucket add sadgoodman https://github.com/sadgoodman/scoop-bucket
scoop install cli-proxy
Дальше scoop update cli-proxy и scoop uninstall cli-proxy. Манифест покрывает
и x86-64, и arm64.
При первой привязке к 0.0.0.0 брандмауэр Windows спросит, разрешить ли
программе доступ в частных сетях — согласитесь, если хотите перехватывать
трафик с телефона или другой машины.
Всё остальное
Скачайте готовый архив из последнего релиза:
| Платформа | Файл |
|---|---|
| Linux x86-64 | cli-proxy_<версия>_linux_amd64.tar.gz |
| Linux arm64 | cli-proxy_<версия>_linux_arm64.tar.gz |
| macOS Apple Silicon | cli-proxy_<версия>_darwin_arm64.tar.gz |
| macOS Intel | cli-proxy_<версия>_darwin_amd64.tar.gz |
| Windows x86-64 | cli-proxy_<версия>_windows_amd64.zip |
В том же релизе лежит checksums.txt с SHA-256 каждого архива.
Распакуйте и положите cli-proxy (или cli-proxy.exe) куда-нибудь в PATH.
Это обычные файлы, а не установщик: ни записей в реестре, ни служб.
Как обновляются пакеты
И формула Homebrew, и манифест Scoop обновляются сами.
sadgoodman/homebrew-tap и sadgoodman/scoop-bucket раз в час
сверяются с последним релизом. Если нужно сразу после выпуска, запустите
workflow Update formulae или Update manifests во вкладке Actions
соответствующего репозитория.
Пакета для Chocolatey и манифеста winget пока нет. Chocolatey потребовал бы
прав администратора при каждой установке и модерации в общем репозитории, что
для одного бинарника мало что даёт; winget требует, чтобы манифесты сначала
попали в microsoft/winget-pkgs.
Сборка
go build -o cli-proxy . # обычная сборка
go build -ldflags="-s -w" -o cli-proxy . # ~6.9 МБ без отладочной информации
Кросс-компиляция без дополнительных инструментов:
GOOS=linux GOARCH=amd64 go build -o cli-proxy-linux .
GOOS=windows GOARCH=amd64 go build -o cli-proxy.exe .
Или через make build, make test, make vet, make fmt.
Быстрый старт
./cli-proxy # TUI на 0.0.0.0:8080
./cli-proxy -port 9090 # тот же хост, другой порт
./cli-proxy -addr 127.0.0.1 -port 9090 # явно и хост, и порт
./cli-proxy -addr 127.0.0.1:9000 # только локально
./cli-proxy -tunnel # без MITM: видно только CONNECT-хосты
./cli-proxy -headless # без UI, поток строк в stdout
Проверка с этой же машины:
curl -x http://127.0.0.1:8080 --cacert ~/.cli-proxy/ca.pem https://example.com
Прокси без перехвата SSL/TLS
Запустите ./cli-proxy -tunnel (или ./cli-proxy -tunnel -headless без TUI).
В этом режиме CA не загружается и не создаётся; устанавливать сертификат
на клиентские устройства не нужно. Проверка:
curl -x http://127.0.0.1:8080 https://example.com
HTTPS проходит через непрозрачный CONNECT-туннель с исходным сертификатом
сервера. Видны адресаты и объёмы данных, но не URL-пути, заголовки или тела
HTTPS-запросов. Правила и breakpoints внутри туннеля не работают. Обычный HTTP
обрабатывается как прежде. Флаг -system-proxy можно сочетать с -tunnel.
Отдельные команды -install-cert и -uninstall-cert по-прежнему выполняют
явно запрошенное действие с сертификатом, даже при указании -tunnel.
В TUI откройте Cert (4) и нажмите m или кнопку TLS off / TLS on.
Текущий режим показан в шапке (MITM / TUNNEL) и во вкладке Cert.
Переключение действует только на новые соединения: существующие продолжают
работать в прежнем режиме до переподключения клиента. При первом включении
перехвата CA загружается или создаётся; установка в доверенные остаётся
отдельным действием. При ошибке загрузки CA сохраняется режим туннеля.
Выбор действует до выхода; при следующем запуске режим задаёт флаг -tunnel.
Смена порта
Порт можно задать флагом, а можно поменять прямо в работающем интерфейсе:
-port 9090— оставляет хост из-addr, меняет только порт.-addr 127.0.0.1 -port 9090— явно и хост, и порт.- В TUI — клавиша
p(или кнопка port внизу экрана, она же в разделе Cert). Принимается как число (9090), так и полный адрес (127.0.0.1:9090).
Смена порта применяется сразу, без перезапуска: уже пойманные потоки, правила, breakpoint’ы и корневой сертификат сохраняются. Новый адрес сначала пытается занять порт, и только при успехе старый слушатель закрывается — поэтому при ошибке (например, «address already in use») прокси продолжает работать на прежнем порту, а причина показывается в статусной строке. Уже открытые соединения не разрываются, они доводятся до конца.
После смены порта не забудьте поменять его и в настройках прокси на устройстве.
В шапке интерфейса и в разделе Cert адрес обновляется автоматически;
при слушании на всех интерфейсах он отображается как *:9090.
Установка сертификата одной кнопкой
Корневой сертификат можно поставить в доверенные прямо из приложения — без скачивания файла и без команд в терминале.
- В интерфейсе: раздел Cert (
3) →i. Кнопка install cert делает то же самое. - Из командной строки:
./cli-proxy -install-cert. - Убрать:
uв том же разделе или./cli-proxy -uninstall-cert.
На macOS установка для текущего пользователя проходит без пароля и без sudo:
сертификат кладётся в связку ключей пользователя с полным доверием
(security add-trusted-cert -r trustRoot). После этого HTTPS-трафик виден в
браузерах, curl и большинстве приложений без всяких --cacert и -k.
Операция выполняется в фоне, поэтому интерфейс не подвисает, пока система
спрашивает разрешение. В шапке на это время появляется cert…, а в разделе
Cert строка Trusted показывает текущее состояние: trusted — macOS keychain
или not trusted by macOS.
| Система | Что делает установка для пользователя | Для всех пользователей (I / -cert-system) |
|---|---|---|
| macOS | security add-trusted-cert в связку ключей пользователя, без пароля |
открывает окно Терминала с sudo security add-trusted-cert -d |
| Windows | certutil -user -addstore ROOT |
certutil -addstore ROOT с запросом UAC |
| Linux | certutil -A в базу NSS (~/.pki/nssdb), её видят Chrome и Chromium |
окно терминала с sudo cp … && sudo update-ca-certificates |
Если macOS всё же требует авторизацию (это случается, когда запись доверия для этого сертификата уже существует), попытка прерывается через несколько секунд и автоматически открывается окно Терминала с той же командой — там запрос можно подтвердить нормально. Так интерфейс никогда не зависает в ожидании клика.
Удаление симметрично: снимается и настройка доверия, и сам сертификат из связки ключей, поэтому состояние возвращается к исходному.
Firefox и некоторые приложения держат собственное хранилище сертификатов и системный корень не используют — их нужно настроить отдельно (инструкция есть на странице
/ssl).
Проксирование с телефона или планшета
- Запустите
cli-proxy— в шапке UI и в разделе Cert (3) будет адрес видаhttp://192.168.1.42:8080. - На устройстве откройте этот адрес и скачайте корневой сертификат.
Короткий адрес. Вводить IP с портом каждый раз не нужно: наберите
http://cli.proxy/ssl — этот запрос всё равно уходит через прокси, поэтому
DNS не нужен, и прокси отвечает сам. Работают также /cert, /cert.der,
/ca.mobileconfig на именах cli.proxy, cliproxy, cliproxy.local,
cert.local и proxy.man (совместимость с Proxyman). Если открыть
https://cli.proxy/ssl, прокси вернёт понятное объяснение вместо ошибки
рукопожатия — сертификат ещё не установлен, нужен именно http://.
- В настройках Wi-Fi укажите прокси вручную: хост — IP компьютера, порт — 8080.
- Раздел Cert в UI (
o— открыть страницу установки в браузере) содержит подробную инструкцию для iOS, Android, macOS, Windows и Firefox.
Коротко:
| Платформа | Установка корня |
|---|---|
| iOS / iPadOS | Safari → /cert → Профиль загружен → Установить → Основные → Об этом устройстве → Доверие сертификатам → включить полное доверие. Либо сразу /ca.mobileconfig. |
| Android | /cert → Настройки → Безопасность → Шифрование и учётные данные → Установить сертификат → Сертификат CA. (Android 7+ не доверяет пользовательским CA приложениям, которые явно это запрещают.) |
| macOS | curl -o cli-proxy-ca.crt http://IP:8080/cli-proxy-ca.crt && sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain cli-proxy-ca.crt |
| Windows | Скачать /cert, затем certutil -addstore -f ROOT cli-proxy-ca.crt |
| Firefox | Своё хранилище: Настройки → Приватность → Сертификаты → Просмотр → Центры сертификации → Импорт. |
| Скрипты | curl -x http://IP:8080 --cacert ca.pem https://… |
CA хранится в ~/.cli-proxy/ (ca.pem, ca-key.pem); путь переопределяется
флагом -ca-dir или переменной CLI_PROXY_HOME.
Локальный трафик с этой же машины
Прокси видит только тот трафик, который на него отправлен. Проще всего включить системный прокси — тогда через cli-proxy пойдёт всё, включая браузеры и GUI-приложения:
./cli-proxy -system-proxy # включить сразу при запуске
Или в интерфейсе: раздел Cert (3) → клавиша s (кнопка sys-proxy).
Состояние видно и в шапке (sys-proxy), и строкой в разделе Cert:
│ System proxy ON -> 127.0.0.1:8080 (restored when cli-proxy exits) │
Прежние настройки возвращаются автоматически. Снимок конфигурации делается
до любых изменений и сохраняется в <ca-dir>/sysproxy-backup.json, а не
только в памяти. Поэтому:
- обычный выход (
q),Ctrl-CиSIGTERM— настройки возвращаются; - ошибка при включении — изменения откатываются сразу;
kill -9, падение питания, паника — при следующем запуске cli-proxy найдёт резервную копию и вернёт конфигурацию до начала работы;- смена порта при включённом системном прокси автоматически перенаправляет его на новый адрес.
Восстанавливаются и флаг включения, и адрес с портом, поэтому состояние совпадает с исходным побайтово. Что именно поддерживается:
| Система | Механизм |
|---|---|
| macOS | networksetup — все включённые сетевые сервисы, web и secure web proxy |
| Windows | реестр HKCU\...\Internet Settings (ProxyEnable, ProxyServer, ProxyOverride) + InternetSetOption, чтобы изменения применились без перезагрузки |
| Linux | GNOME через gsettings (mode, http, https) |
На остальных системах кнопка сообщит, что управление недоступно.
Если системный прокси включать не хочется, направьте программы вручную:
export HTTP_PROXY=http://127.0.0.1:8080
export HTTPS_PROXY=http://127.0.0.1:8080
curl -o cli-proxy-ca.crt http://127.0.0.1:8080/cli-proxy-ca.crt
curl -x http://127.0.0.1:8080 --cacert cli-proxy-ca.crt https://example.com
curl -x http://127.0.0.1:8080 -k https://example.com # без установки корня
Почему локальный трафик может не появляться. macOS и Windows по умолчанию исключают из прокси адреса
127.0.0.1,localhostи*.local. Обращения к сервисам на этой же машине идут мимо прокси, даже когда системный прокси включён. Уберите эти записи из списка исключений, если их нужно видеть. Обращения к внешним сайтам перехватываются нормально.
Отдельно: запросы к страницам самого прокси (/ssl, /cert, /status) не
попадают в список потоков — это не проксированный трафик. Они пишутся в раздел
Log с пометкой direct или local-host, так что видно, что прокси вас
слышит.
Панели запроса и ответа
Внизу списка потоков и в полноэкранном просмотре запрос и ответ показываются рядом: слева запрос, справа ответ. У каждой панели своя полоса табов:
╭─ request · GET https://api.example.com/v1/users ───── headers · body · raw ─╮
│ GET /v1/users HTTP/1.1 │
│ Host: api.example.com │
╰─────────────────────────────────────────────────────────────────────────────╯
headers— стартовая строка и заголовки, без тела;body— только тело, с форматированием JSON и подсветкой;raw— всё сообщение целиком, как оно ушло по проводу.
Управление:
| Клавиши | Действие |
|---|---|
Tab |
переключить активную панель (запрос ↔ ответ) |
Shift-Tab |
сменить таб активной панели |
h / r |
сразу перейти к headers / raw |
b |
body (в полноэкранном просмотре; в списке b — это breakpoint) |
[ / ] |
свернуть левую / правую панель |
\ |
показать обе панели снова |
| клик по табу | выбрать таб и сделать панель активной |
↑ ↓ PgUp PgDn |
прокрутка активной панели |
Активная панель обведена ярче. Когда одна из панелей свёрнута, вторая занимает всю ширину, а внутри неё внизу подсказка, как вернуть скрытую.
JSON и длинные строки
Тело с Content-Type: application/json (или просто начинающееся с { или [)
переформатируется с отступами и раскрашивается: ключи, строки, числа и
литералы — разными цветами. Длинные строки переносятся, а не обрезаются,
причём перенос старается идти по пробелам, чтобы значение не разрывалось
посередине. Если включён -keep-encoding и сервер ответил brotli, вместо
бинарного мусора выводится явное объяснение.
Сохранённые фильтры
Строка фильтра (f) — временная: Esc её очищает. Чтобы фильтр работал
постоянно, сохраните его на вкладке Filters (2):
| Клавиши | Действие |
|---|---|
space (или клик) |
включить/выключить выбранный фильтр |
a |
добавить фильтр |
e |
изменить выбранный |
d |
удалить выбранный |
c |
удалить все |
p |
закрепить то, что сейчас набрано в строке фильтра |
Все включённые сохранённые фильтры объединяются по И и применяются вместе с
временным фильтром из строки. Число активных показано в шапке (2 saved
filter), а в заголовке списка — +2 saved. Фильтры хранятся в
~/.cli-proxy/filters.json (флаг -filters) и переживают перезапуск.
Управление
Клавиатура
| Клавиши | Действие |
|---|---|
← → / 1–6 |
переключение пунктов меню |
↑ ↓ / j k |
перемещение по списку |
PgUp PgDn Home End |
страницами и в начало/конец |
Enter / двойной клик |
полный просмотр запроса и ответа |
f или / |
фильтр и поиск (применяется на лету) |
b / B |
breakpoint на все запросы / ответы |
x |
отпустить все остановленные breakpoint’ы |
m |
сохранить тело ответа в файл и создать правило file= |
M |
создать правило redirect= на другой адрес |
i |
создать правило break=both для этого URL |
s |
сохранить весь обмен в файл |
p |
сменить порт прослушивания (применяется сразу) |
i (в разделе Cert) |
поставить корневой сертификат в доверенные |
I (в разделе Cert) |
то же, но для всех пользователей |
u (в разделе Cert) |
убрать сертификат из доверенных |
s (в разделе Cert) |
включить/выключить системный прокси этой машины |
m (в разделе Cert) |
включить/выключить перехват TLS для новых соединений |
c |
очистить список |
Tab / Shift-Tab |
активная панель / таб панели (см. выше) |
h b r |
табы панели: заголовки, тело, сырое сообщение |
[ ] \ |
свернуть левую / правую панель, показать обе |
? |
справка |
q / Ctrl-C |
выход |
В редакторе breakpoint’а: обычный набор текста, Enter — новая строка,
Ctrl-S (или F10) — отправить, Esc — отбросить обмен.
В разделе Rules: Space — включить/выключить правило, a — добавить,
e — изменить, d — удалить, c — удалить все.
В подсказке порт вводится как число или как хост:порт; Enter применяет,
Esc отменяет.
Мышь
- Наведение подсвечивает строку таблицы, вкладку или кнопку.
- Клик выбирает строку, переключает вкладку, нажимает кнопку внизу экрана.
- Двойной клик по строке открывает детальный просмотр.
- Колесо прокручивает списки и панели; в редакторе клик ставит курсор.
Фильтры и поиск
Токены, стоящие рядом, объединяются по И; | (или слово OR) — по ИЛИ;
скобки задают группировку.
| Токен | Значение |
|---|---|
users |
подстрока в URL (без учёта регистра) |
/v1/.*json/ |
регулярное выражение по полному URL |
method:GET,POST |
метод |
status:2xx, status:404, status:>=400 |
код ответа |
status:0, status:err |
потоки, которые так и не получили ответ |
host:api.example.com |
подстрока в хосте |
body:token |
подстрока в теле запроса или ответа |
tag:mock |
метка потока (mock, redirect, edit, tunnel, break, upgrade) |
scheme:https |
схема |
!токен |
отрицание любого токена |
a \| b, a OR b |
ИЛИ |
(a \| b) c |
группировка скобками |
Примеры:
method:GET status:>=400 !host:cdn /api/v1/ # И
/users$/ | /orders$/ # ИЛИ
(method:GET | method:POST) status:5xx # (GET или POST) и 5xx
host:api.example.com | host:cdn.example.com # два хоста
Пока открыт ввод фильтра, список продолжает листаться: ↑/↓/PgUp/PgDn
двигают выделение, а ←/→/Home/End — каретку внутри строки фильтра.
Клик мышью по строке тоже работает, не закрывая ввод. Регулярное выражение
внутри /…/ не должно содержать пробелов — пробел считается разделителем
токенов.
Правила
Правило — одна строка DSL:
[METHOD] URL_REGEX :: действие[=аргумент] :: действие[=аргумент] ...
METHOD — *, конкретный метод или список через запятую. URL_REGEX
проверяется и по полному URL, и по path+query, поэтому работают оба варианта:
^https://api\.example\.com/v1 и ^/v1.
Действия:
| Действие | Что делает |
|---|---|
file=/tmp/mock.json |
ответить содержимым локального файла (запрос на сервер не уходит) |
redirect=https://staging/… |
прокси сам запрашивает другой адрес и отдаёт его ответ |
location=https://other/… |
ответить настоящим 302 на другой адрес |
status=503 |
подменить код ответа |
body={"down":true} |
подменить тело ответа |
header=X-Debug=1 |
установить заголовок запроса |
delheader=Cookie |
удалить заголовок запроса |
resheader=X-Env=test |
установить заголовок ответа |
delresheader=Set-Cookie |
удалить заголовок ответа |
break=req | resp | both |
остановить для ручной правки |
block=403 |
отклонить запрос |
delay=750ms |
добавить задержку |
maplocal=/static/=/var/www |
отдавать каталог под префиксом URL |
Примеры:
GET ^http://127\.0\.0\.1:8080/v1/users$ :: file=/tmp/users.json
GET .*/legacy-endpoint$ :: redirect=https://staging.example.com/legacy-endpoint
* ^http://cdn\.example\.net/logo\.png :: location=https://cdn.example.com/logo.png
* example\.com :: header=X-Debug=1 :: break=both
* ^http://api\.example\.com/flaky :: status=503 :: body={"maintenance":true}
* ^http://ads\.example\.com/ :: block=204
* ^http://slow\.example\.com/ :: delay=1500ms
* ^http://app\.example\.com/static/ :: maplocal=/static/=/var/www/app
Правила хранятся в ~/.cli-proxy/rules.json и сохраняются при каждом изменении.
Массовый импорт:
./cli-proxy -import-rules rules.txt
Их можно создавать прямо из списка потоков: m (мок из тела ответа), M
(редирект), i (перехват) — правило подставляется с заэкранированным URL.
Breakpoints
Правило break=req, break=resp или break=both (либо глобальные переключатели
b / B) останавливают обмен. UI автоматически открывает редактор с сырым
HTTP-сообщением:
╭─ breakpoint #1 · REQUEST — edit headers, method, URL or body, then send ─╮
│ 1│ POST /v1/orders HTTP/1.1 │
│ 2│ Host: api.example.com │
│ 3│ Content-Type: application/json │
│ 4│ │
│ 5│ {"amount":10,"currency":"EUR"} │
╰──────────────────────────────────────────────────────────────────────────╯
Ctrl-S — отправить изменённое сообщение, Esc — отбросить (клиент получит
502). Длина тела пересчитывается автоматически, поэтому Content-Length
можно не трогать. Одновременно можно держать несколько остановленных обменов —
они выстраиваются в очередь, счётчик виден в шапке.
Флаги
| Флаг | По умолчанию | Описание |
|---|---|---|
-addr |
0.0.0.0:8080 |
адрес прослушивания |
-port |
0 (взять из -addr) |
порт; переопределяет порт из -addr, хост сохраняется |
-tunnel |
false |
не расшифровывать TLS, только туннелировать CONNECT |
-ca-dir |
~/.cli-proxy |
каталог с корневым сертификатом и ключом |
-rules |
<ca-dir>/rules.json |
файл правил |
-filters |
<ca-dir>/filters.json |
файл сохранённых фильтров |
-max-body |
8388608 |
максимум байт тела на сообщение |
-flows |
2000 |
сколько потоков хранить в памяти |
-insecure |
false |
не проверять сертификат вышестоящего сервера |
-ca-bundle |
дополнительный PEM-бандл доверенных корней | |
-keep-encoding |
false |
не трогать Accept-Encoding (тела в brotli/zstd будут показаны как бинарные) |
-system-proxy |
false |
направить системный прокси этой машины на cli-proxy и вернуть прежние настройки при выходе |
-install-cert |
false |
поставить корневой сертификат в доверенные и выйти |
-uninstall-cert |
false |
убрать корневой сертификат из доверенных и выйти |
-cert-system |
false |
с -install-cert/-uninstall-cert — для всех пользователей |
-headless |
false |
без UI, строки потоков в stdout |
-import-rules |
импортировать файл DSL-правил и выйти | |
-version |
версия |
Структура
main.go флаги, баннер, headless-режим
internal/ca/ корневой CA, листовые сертификаты, кэш
internal/core/
flow.go модель запроса/ответа, рендер raw-сообщений
store.go кольцевой буфер потоков с подпиской на изменения
rules.go DSL правил, хранение, сопоставление
filter.go сохранённые фильтры с хранением на диске
breakpoint.go очередь остановленных обменов
query.go язык фильтров
log.go журнал движка
internal/proxy/
proxy.go HTTP-прокси, CONNECT, MITM, WebSocket, правила
local.go /cert, /cert.der, /ca.mobileconfig, /status
internal/sysproxy/ системный прокси: снимок, применение, восстановление
internal/trust/ установка и удаление корневого сертификата
internal/term/ raw-режим, размер окна, разбор клавиш и SGR-мыши
internal/tui/
screen.go клеточный буфер и дифф-рендер в ANSI
theme.go палитра и скруглённые рамки
table.go таблицы и боксы со скруглёнными углами
(в views.go — панели с табами, перенос по словам,
подсветка JSON, два столбца справки)
editor.go редактор raw-HTTP
app.go состояние, цикл событий, клавиатура и мышь
views.go отрисовка всех экранов
Разработка
make build # собрать
make test # прогнать тесты
make vet # go vet
make fmt # gofmt
make cross # собрать под все поддерживаемые платформы
Непрерывная интеграция
.github/workflows/ci.yml на каждый push в master и на pull request:
go vet,gofmt -lиgo test ./...на Linux, macOS и Windows;- отдельный прогон с
-raceна Linux; - кросс-компиляция под 7 целей (linux/amd64, linux/arm64, darwin/amd64, darwin/arm64, windows/amd64, windows/arm64, freebsd/amd64).
Как выпустить релиз
.github/workflows/release.yml реагирует на тег вида v*:
- сверяет версию из
main.goс тегом и падает, если они разошлись; - собирает архивы через GoReleaser (
goreleaser release), проверяет контрольные суммы и запускает собранный linux-бинарник; - публикует GitHub Release с архивами,
checksums.txtи списком коммитов с прошлого тега.
# поднять версию в main.go, закоммитить, затем:
git tag -a v0.2.0 -m "cli-proxy v0.2.0"
git push origin v0.2.0
Workflow можно запустить вручную из вкладки Actions — тогда он соберёт архивы и положит их в артефакты запуска, ничего не публикуя.
Тесты
go test ./...
Покрыто: сквозное проксирование HTTP и HTTPS с перехватом, все действия правил, отказ от нечитаемых кодировок и короткий адрес сертификата, «И/ИЛИ/скобки» в фильтрах, навигация по списку при открытом фильтре, разбор hover-событий мыши, табы и сворачивание панелей, форматирование и перенос JSON, сохранённые фильтры и их слияние со строкой фильтра, двухколоночная справка, жизненный цикл системного прокси (снимок, откат при ошибке, восстановление после аварийного завершения), установка и удаление корневого сертификата, включая фоновое выполнение и сборку команд с экранированием, правка запроса и ответа через breakpoint, отбрасывание обмена, режим туннеля, раздача сертификата, свойства листовых сертификатов, DSL и фильтры, смена порта на лету (включая отказ при занятом порте и сохранение потоков), разбор escape-последовательностей клавиатуры и SGR-мыши, геометрия скруглённых таблиц, полная отрисовка всех экранов, доступность кнопок на любой ширине и реакция на мышь.