9router 0.3.53 → 0.3.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/.next/BUILD_ID +1 -1
- package/app/.next/app-path-routes-manifest.json +45 -45
- package/app/.next/build-manifest.json +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/page.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/_global-error.html +2 -2
- package/app/.next/server/app/_global-error.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/_not-found.html +1 -1
- package/app/.next/server/app/_not-found.rsc +4 -4
- package/app/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/app/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/antigravity-mitm/alias/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/antigravity-mitm/route.js +1 -1
- package/app/.next/server/app/api/cli-tools/antigravity-mitm/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/claude-settings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/codex-settings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/copilot-settings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/droid-settings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/openclaw-settings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/opencode-settings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cloud/auth/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cloud/credentials/update/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cloud/model/resolve/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cloud/models/alias/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/combos/[id]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/combos/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/keys/[id]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/keys/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/locale/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/models/alias/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/models/route.js +1 -1
- package/app/.next/server/app/api/models/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/models/test/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/[provider]/[action]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/cursor/auto-import/route.js +1 -1
- package/app/.next/server/app/api/oauth/cursor/auto-import/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/cursor/import/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/iflow/cookie/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/kiro/auto-import/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/kiro/import/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/kiro/social-authorize/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/kiro/social-exchange/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/pricing/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/provider-nodes/[id]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/provider-nodes/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/provider-nodes/validate/route.js +1 -1
- package/app/.next/server/app/api/provider-nodes/validate/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/[id]/models/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/[id]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/[id]/test/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/[id]/test-models/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/client/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/route.js +1 -1
- package/app/.next/server/app/api/providers/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/test-batch/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/validate/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/proxy-pools/[id]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/proxy-pools/[id]/test/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/proxy-pools/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/settings/database/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/settings/proxy-test/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/settings/require-login/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/tags/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/translator/console-logs/route.js +1 -1
- package/app/.next/server/app/api/translator/console-logs/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/translator/console-logs/stream/route.js +1 -1
- package/app/.next/server/app/api/translator/console-logs/stream/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/translator/load/route.js.nft.json +1 -1
- package/app/.next/server/app/api/translator/load/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/translator/save/route.js.nft.json +1 -1
- package/app/.next/server/app/api/translator/save/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/translator/send/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/translator/translate/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/tunnel/disable/route.js +1 -1
- package/app/.next/server/app/api/tunnel/disable/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/tunnel/enable/route.js +1 -1
- package/app/.next/server/app/api/tunnel/enable/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/tunnel/status/route.js +1 -1
- package/app/.next/server/app/api/tunnel/status/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/[connectionId]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/chart/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/history/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/providers/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/request-details/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/request-logs/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/stats/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/stream/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/api/chat/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/chat/completions/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/embeddings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/messages/count_tokens/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/messages/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/models/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/responses/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1beta/models/[...path]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1beta/models/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/version/route.js +1 -1
- package/app/.next/server/app/api/version/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/callback/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/callback.html +1 -1
- package/app/.next/server/app/callback.rsc +4 -4
- package/app/.next/server/app/callback.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/callback.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/callback.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/callback.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/callback.segments/callback/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/callback.segments/callback.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/cli-tools.html +1 -1
- package/app/.next/server/app/dashboard/cli-tools.rsc +6 -6
- package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/cli-tools.segments/_full.segment.rsc +6 -6
- package/app/.next/server/app/dashboard/cli-tools.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/cli-tools.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/combos.html +1 -1
- package/app/.next/server/app/dashboard/combos.rsc +6 -6
- package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/combos.segments/_full.segment.rsc +6 -6
- package/app/.next/server/app/dashboard/combos.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/combos.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/combos.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/endpoint.html +1 -1
- package/app/.next/server/app/dashboard/endpoint.rsc +6 -6
- package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/endpoint.segments/_full.segment.rsc +6 -6
- package/app/.next/server/app/dashboard/endpoint.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/endpoint.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/endpoint.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/mitm.html +1 -1
- package/app/.next/server/app/dashboard/mitm.rsc +6 -6
- package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/mitm.segments/_full.segment.rsc +6 -6
- package/app/.next/server/app/dashboard/mitm.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/mitm.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/mitm.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/profile.html +1 -1
- package/app/.next/server/app/dashboard/profile.rsc +6 -6
- package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/profile.segments/_full.segment.rsc +6 -6
- package/app/.next/server/app/dashboard/profile.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/profile.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/profile.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers/new.html +1 -1
- package/app/.next/server/app/dashboard/providers/new.rsc +6 -6
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers/new.segments/_full.segment.rsc +6 -6
- package/app/.next/server/app/dashboard/providers/new.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/providers/new.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers.html +1 -1
- package/app/.next/server/app/dashboard/providers.rsc +6 -6
- package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers.segments/_full.segment.rsc +6 -6
- package/app/.next/server/app/dashboard/providers.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/providers.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/proxy-pools.html +1 -1
- package/app/.next/server/app/dashboard/proxy-pools.rsc +6 -6
- package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +6 -6
- package/app/.next/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/quota.html +2 -2
- package/app/.next/server/app/dashboard/quota.rsc +5 -5
- package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/quota.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/dashboard/quota.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/quota.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/quota.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.html +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.rsc +4 -4
- package/app/.next/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/translator.html +1 -1
- package/app/.next/server/app/dashboard/translator.rsc +6 -6
- package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/translator.segments/_full.segment.rsc +6 -6
- package/app/.next/server/app/dashboard/translator.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/translator.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/translator.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/usage.html +1 -1
- package/app/.next/server/app/dashboard/usage.rsc +6 -6
- package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/usage.segments/_full.segment.rsc +6 -6
- package/app/.next/server/app/dashboard/usage.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/usage.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/usage.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/dashboard.html +1 -1
- package/app/.next/server/app/dashboard.rsc +6 -6
- package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard.segments/_full.segment.rsc +6 -6
- package/app/.next/server/app/dashboard.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/dashboard.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/index.html +1 -1
- package/app/.next/server/app/index.rsc +4 -4
- package/app/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/index.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/landing/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/landing.html +1 -1
- package/app/.next/server/app/landing.rsc +4 -4
- package/app/.next/server/app/landing.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/landing.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/landing.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/landing.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/landing.segments/landing/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/landing.segments/landing.segment.rsc +1 -1
- package/app/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/login.html +1 -1
- package/app/.next/server/app/login.rsc +5 -5
- package/app/.next/server/app/login.segments/_full.segment.rsc +5 -5
- package/app/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/login.segments/_index.segment.rsc +4 -4
- package/app/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/app/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/login.segments/login.segment.rsc +1 -1
- package/app/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -1
- package/app/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app-paths-manifest.json +45 -45
- package/app/.next/server/chunks/1114.js +1 -1
- package/app/.next/server/chunks/1424.js +1 -1
- package/app/.next/server/chunks/318.js +1 -1
- package/app/.next/server/chunks/6182.js +4 -17
- package/app/.next/server/chunks/649.js +1 -1
- package/app/.next/server/chunks/9201.js +1 -1
- package/app/.next/server/pages/404.html +1 -1
- package/app/.next/server/pages/500.html +2 -2
- package/app/.next/server/server-reference-manifest.js +1 -1
- package/app/.next/server/server-reference-manifest.json +1 -1
- package/app/.next/static/chunks/{5497-2f4b5d7837ad4dc8.js → 5497-9933573cfe960e0c.js} +1 -1
- package/app/.next/static/chunks/{9242-3fb6423adcc6e277.js → 9242-3e0fdad972d9b35d.js} +2 -2
- package/app/.next/static/chunks/app/(dashboard)/dashboard/providers/[id]/{page-4ebc425afc0a221a.js → page-5e7e72628fe63cec.js} +1 -1
- package/app/.next/static/chunks/app/(dashboard)/dashboard/providers/page-bf901cec2b7f0ea0.js +1 -0
- package/app/.next/static/chunks/app/{layout-d66315546ced1415.js → layout-08e56eacc7acf9e1.js} +1 -1
- package/app/.next/static/css/{0c4f3a92a0a64981.css → 4016074f63f34af9.css} +1 -1
- package/app/package.json +1 -1
- package/app/src/mitm/cert/install.js +14 -14
- package/app/src/mitm/cert/rootCA.js +22 -2
- package/app/src/mitm/dns/dnsConfig.js +13 -66
- package/app/src/mitm/logger.js +8 -0
- package/app/src/mitm/manager.js +98 -78
- package/app/src/mitm/server.js +28 -17
- package/cli.js +6 -8
- package/package.json +1 -1
- package/app/.next/static/chunks/app/(dashboard)/dashboard/providers/page-3143d3dbb2dc3422.js +0 -1
- /package/app/.next/static/{2ABcpZEvM8MzFMmHIRKq0 → lSUZX6G8rzoxhxgvfuJ7I}/_buildManifest.js +0 -0
- /package/app/.next/static/{2ABcpZEvM8MzFMmHIRKq0 → lSUZX6G8rzoxhxgvfuJ7I}/_ssgManifest.js +0 -0
|
@@ -2,6 +2,7 @@ const { exec, spawn } = require("child_process");
|
|
|
2
2
|
const fs = require("fs");
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const os = require("os");
|
|
5
|
+
const { log, err } = require("../logger");
|
|
5
6
|
|
|
6
7
|
// Per-tool DNS hosts mapping
|
|
7
8
|
const TOOL_HOSTS = {
|
|
@@ -131,7 +132,7 @@ async function addDNSEntry(tool, sudoPassword) {
|
|
|
131
132
|
|
|
132
133
|
const entriesToAdd = hosts.filter(h => !checkDNSEntry(h));
|
|
133
134
|
if (entriesToAdd.length === 0) {
|
|
134
|
-
|
|
135
|
+
log(`🌐 DNS ${tool}: already active`);
|
|
135
136
|
return;
|
|
136
137
|
}
|
|
137
138
|
|
|
@@ -139,43 +140,15 @@ async function addDNSEntry(tool, sudoPassword) {
|
|
|
139
140
|
|
|
140
141
|
try {
|
|
141
142
|
if (IS_WIN) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
scriptLines.push(`$ErrorActionPreference = 'Stop'`);
|
|
147
|
-
scriptLines.push(`$hostsPath = '${hostsPath}'`);
|
|
148
|
-
scriptLines.push(`try {`);
|
|
149
|
-
scriptLines.push(` $hostsContent = Get-Content -Path $hostsPath -Raw -ErrorAction SilentlyContinue`);
|
|
150
|
-
scriptLines.push(` if (-not $hostsContent) { $hostsContent = '' }`);
|
|
151
|
-
|
|
152
|
-
for (const host of entriesToAdd) {
|
|
153
|
-
// Escape special regex chars in hostname
|
|
154
|
-
const escapedHost = host.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
155
|
-
scriptLines.push(` if ($hostsContent -notmatch '${escapedHost}') {`);
|
|
156
|
-
scriptLines.push(` Add-Content -Path $hostsPath -Value '127.0.0.1 ${host}' -Encoding UTF8 -ErrorAction Stop`);
|
|
157
|
-
scriptLines.push(` Write-Host "Added DNS entry: ${host}"`);
|
|
158
|
-
scriptLines.push(` } else {`);
|
|
159
|
-
scriptLines.push(` Write-Host "DNS entry already exists: ${host}"`);
|
|
160
|
-
scriptLines.push(` }`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
scriptLines.push(` ipconfig /flushdns | Out-Null`);
|
|
164
|
-
scriptLines.push(`} catch {`);
|
|
165
|
-
scriptLines.push(` Write-Error "Failed to add DNS: $_"`);
|
|
166
|
-
scriptLines.push(` exit 1`);
|
|
167
|
-
scriptLines.push(`}`);
|
|
168
|
-
|
|
169
|
-
const psScript = scriptLines.join("\n");
|
|
170
|
-
const tmpPs1 = path.join(os.tmpdir(), `mitm_dns_add_${Date.now()}.ps1`);
|
|
171
|
-
fs.writeFileSync(tmpPs1, psScript, "utf8");
|
|
172
|
-
|
|
173
|
-
await executeElevatedPowerShell(tmpPs1, 30000);
|
|
143
|
+
// Process already has admin rights — edit hosts file directly
|
|
144
|
+
const toAppend = entriesToAdd.map(h => `127.0.0.1 ${h}`).join("\r\n") + "\r\n";
|
|
145
|
+
fs.appendFileSync(HOSTS_FILE, toAppend, "utf8");
|
|
146
|
+
require("child_process").execSync("ipconfig /flushdns", { windowsHide: true });
|
|
174
147
|
} else {
|
|
175
148
|
await execWithPassword(`echo "${entries}" >> ${HOSTS_FILE}`, sudoPassword);
|
|
176
149
|
await flushDNS(sudoPassword);
|
|
177
150
|
}
|
|
178
|
-
|
|
151
|
+
log(`🌐 DNS ${tool}: ✅ added ${entriesToAdd.join(", ")}`);
|
|
179
152
|
} catch (error) {
|
|
180
153
|
const msg = error.message?.includes("incorrect password") ? "Wrong sudo password" : "Failed to add DNS entry";
|
|
181
154
|
throw new Error(msg);
|
|
@@ -191,43 +164,17 @@ async function removeDNSEntry(tool, sudoPassword) {
|
|
|
191
164
|
|
|
192
165
|
const entriesToRemove = hosts.filter(h => checkDNSEntry(h));
|
|
193
166
|
if (entriesToRemove.length === 0) {
|
|
194
|
-
|
|
167
|
+
log(`🌐 DNS ${tool}: already inactive`);
|
|
195
168
|
return;
|
|
196
169
|
}
|
|
197
170
|
|
|
198
171
|
try {
|
|
199
172
|
if (IS_WIN) {
|
|
173
|
+
// Process already has admin rights — edit hosts file directly
|
|
200
174
|
const content = fs.readFileSync(HOSTS_FILE, "utf8");
|
|
201
175
|
const filtered = content.split(/\r?\n/).filter(l => !entriesToRemove.some(h => l.includes(h))).join("\r\n");
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const tmpEsc = tmpFile.replace(/'/g, "''");
|
|
206
|
-
const hostsEsc = HOSTS_FILE.replace(/'/g, "''");
|
|
207
|
-
|
|
208
|
-
// Build PowerShell script with proper error handling
|
|
209
|
-
const scriptLines = [];
|
|
210
|
-
scriptLines.push(`$ErrorActionPreference = 'Stop'`);
|
|
211
|
-
scriptLines.push(`try {`);
|
|
212
|
-
scriptLines.push(` Copy-Item -Path '${tmpEsc}' -Destination '${hostsEsc}' -Force -ErrorAction Stop`);
|
|
213
|
-
scriptLines.push(` Write-Host "Hosts file updated successfully"`);
|
|
214
|
-
scriptLines.push(` ipconfig /flushdns | Out-Null`);
|
|
215
|
-
scriptLines.push(` Write-Host "DNS cache flushed"`);
|
|
216
|
-
scriptLines.push(` Remove-Item '${tmpEsc}' -ErrorAction SilentlyContinue`);
|
|
217
|
-
scriptLines.push(`} catch {`);
|
|
218
|
-
scriptLines.push(` Write-Error "Failed to remove DNS: $_"`);
|
|
219
|
-
scriptLines.push(` Remove-Item '${tmpEsc}' -ErrorAction SilentlyContinue`);
|
|
220
|
-
scriptLines.push(` exit 1`);
|
|
221
|
-
scriptLines.push(`}`);
|
|
222
|
-
|
|
223
|
-
const psScript = scriptLines.join("\n");
|
|
224
|
-
const tmpPs1 = path.join(os.tmpdir(), `mitm_dns_remove_${Date.now()}.ps1`);
|
|
225
|
-
fs.writeFileSync(tmpPs1, psScript, "utf8");
|
|
226
|
-
|
|
227
|
-
await executeElevatedPowerShell(tmpPs1, 30000);
|
|
228
|
-
|
|
229
|
-
// Cleanup temp file if still exists
|
|
230
|
-
try { fs.unlinkSync(tmpFile); } catch { /* ignore */ }
|
|
176
|
+
fs.writeFileSync(HOSTS_FILE, filtered, "utf8");
|
|
177
|
+
require("child_process").execSync("ipconfig /flushdns", { windowsHide: true });
|
|
231
178
|
} else {
|
|
232
179
|
for (const host of entriesToRemove) {
|
|
233
180
|
const sedCmd = IS_MAC
|
|
@@ -237,7 +184,7 @@ async function removeDNSEntry(tool, sudoPassword) {
|
|
|
237
184
|
}
|
|
238
185
|
await flushDNS(sudoPassword);
|
|
239
186
|
}
|
|
240
|
-
|
|
187
|
+
log(`🌐 DNS ${tool}: ✅ removed ${entriesToRemove.join(", ")}`);
|
|
241
188
|
} catch (error) {
|
|
242
189
|
const msg = error.message?.includes("incorrect password") ? "Wrong sudo password" : "Failed to remove DNS entry";
|
|
243
190
|
throw new Error(msg);
|
|
@@ -252,7 +199,7 @@ async function removeAllDNSEntries(sudoPassword) {
|
|
|
252
199
|
try {
|
|
253
200
|
await removeDNSEntry(tool, sudoPassword);
|
|
254
201
|
} catch (e) {
|
|
255
|
-
|
|
202
|
+
err(`DNS ${tool}: failed to remove — ${e.message}`);
|
|
256
203
|
}
|
|
257
204
|
}
|
|
258
205
|
}
|
package/app/src/mitm/manager.js
CHANGED
|
@@ -5,12 +5,14 @@ const os = require("os");
|
|
|
5
5
|
const net = require("net");
|
|
6
6
|
const https = require("https");
|
|
7
7
|
const crypto = require("crypto");
|
|
8
|
-
const { addDNSEntry, removeDNSEntry, removeAllDNSEntries, checkAllDNSStatus,
|
|
8
|
+
const { addDNSEntry, removeDNSEntry, removeAllDNSEntries, checkAllDNSStatus, TOOL_HOSTS } = require("./dns/dnsConfig");
|
|
9
9
|
|
|
10
10
|
const IS_WIN = process.platform === "win32";
|
|
11
11
|
const { generateCert } = require("./cert/generate");
|
|
12
|
-
const { installCert } = require("./cert/install");
|
|
12
|
+
const { installCert, uninstallCert } = require("./cert/install");
|
|
13
|
+
const { isCertExpired } = require("./cert/rootCA");
|
|
13
14
|
const { MITM_DIR } = require("./paths");
|
|
15
|
+
const { log, err } = require("./logger");
|
|
14
16
|
|
|
15
17
|
const MITM_PORT = 443;
|
|
16
18
|
const MITM_WIN_NODE_PORT = 8443;
|
|
@@ -80,7 +82,7 @@ function isProcessAlive(pid) {
|
|
|
80
82
|
function killProcess(pid, force = false, sudoPassword = null) {
|
|
81
83
|
if (IS_WIN) {
|
|
82
84
|
const flag = force ? "/F " : "";
|
|
83
|
-
exec(`taskkill ${flag}/PID ${pid}`, () => { });
|
|
85
|
+
exec(`taskkill ${flag}/PID ${pid}`, { windowsHide: true }, () => { });
|
|
84
86
|
} else {
|
|
85
87
|
const sig = force ? "SIGKILL" : "SIGTERM";
|
|
86
88
|
const cmd = `pkill -${sig} -P ${pid} 2>/dev/null; kill -${sig} ${pid} 2>/dev/null`;
|
|
@@ -140,7 +142,7 @@ async function saveMitmSettings(enabled, password) {
|
|
|
140
142
|
if (password) updates.mitmSudoEncrypted = encryptPassword(password);
|
|
141
143
|
await _updateSettings(updates);
|
|
142
144
|
} catch (e) {
|
|
143
|
-
|
|
145
|
+
err(`Failed to save settings: ${e.message}`);
|
|
144
146
|
}
|
|
145
147
|
}
|
|
146
148
|
|
|
@@ -277,8 +279,10 @@ async function getMitmStatus() {
|
|
|
277
279
|
const dnsStatus = checkAllDNSStatus();
|
|
278
280
|
const rootCACertPath = path.join(MITM_DIR, "rootCA.crt");
|
|
279
281
|
const certExists = fs.existsSync(rootCACertPath);
|
|
282
|
+
const { checkCertInstalled } = require("./cert/install");
|
|
283
|
+
const certTrusted = certExists ? await checkCertInstalled(rootCACertPath) : false;
|
|
280
284
|
|
|
281
|
-
return { running, pid, certExists, dnsStatus };
|
|
285
|
+
return { running, pid, certExists, certTrusted, dnsStatus };
|
|
282
286
|
}
|
|
283
287
|
|
|
284
288
|
async function scheduleMitmRestart(apiKey) {
|
|
@@ -288,7 +292,7 @@ async function scheduleMitmRestart(apiKey) {
|
|
|
288
292
|
if (aliveMs >= MITM_RESTART_RESET_MS) mitmRestartCount = 0;
|
|
289
293
|
|
|
290
294
|
if (mitmRestartCount >= MITM_MAX_RESTARTS) {
|
|
291
|
-
|
|
295
|
+
err("Max restart attempts reached. Giving up.");
|
|
292
296
|
return;
|
|
293
297
|
}
|
|
294
298
|
|
|
@@ -297,28 +301,28 @@ async function scheduleMitmRestart(apiKey) {
|
|
|
297
301
|
mitmRestartCount++;
|
|
298
302
|
mitmIsRestarting = true;
|
|
299
303
|
|
|
300
|
-
|
|
304
|
+
log(`Restarting in ${delay / 1000}s... (${mitmRestartCount}/${MITM_MAX_RESTARTS})`);
|
|
301
305
|
await new Promise((r) => setTimeout(r, delay));
|
|
302
306
|
|
|
303
307
|
try {
|
|
304
308
|
const settings = _getSettings ? await _getSettings() : null;
|
|
305
309
|
if (settings && !settings.mitmEnabled) {
|
|
306
|
-
|
|
310
|
+
log("MITM disabled, skipping restart");
|
|
307
311
|
mitmIsRestarting = false;
|
|
308
312
|
return;
|
|
309
313
|
}
|
|
310
314
|
const password = getCachedPassword() || await loadEncryptedPassword();
|
|
311
315
|
if (!password && !IS_WIN) {
|
|
312
|
-
|
|
316
|
+
err("No cached password, cannot auto-restart");
|
|
313
317
|
mitmIsRestarting = false;
|
|
314
318
|
return;
|
|
315
319
|
}
|
|
316
320
|
await startServer(apiKey, password);
|
|
317
|
-
|
|
321
|
+
log("🔄 Restarted successfully");
|
|
318
322
|
mitmRestartCount = 0;
|
|
319
323
|
mitmIsRestarting = false;
|
|
320
|
-
} catch (
|
|
321
|
-
|
|
324
|
+
} catch (e) {
|
|
325
|
+
err(`Restart attempt ${mitmRestartCount}/${MITM_MAX_RESTARTS} failed: ${e.message}`);
|
|
322
326
|
mitmIsRestarting = false;
|
|
323
327
|
// Schedule next retry
|
|
324
328
|
scheduleMitmRestart(apiKey);
|
|
@@ -335,7 +339,7 @@ async function startServer(apiKey, sudoPassword) {
|
|
|
335
339
|
const savedPid = parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10);
|
|
336
340
|
if (savedPid && isProcessAlive(savedPid)) {
|
|
337
341
|
serverPid = savedPid;
|
|
338
|
-
|
|
342
|
+
log(`♻️ Reusing existing process (PID: ${savedPid})`);
|
|
339
343
|
await saveMitmSettings(true, sudoPassword);
|
|
340
344
|
if (sudoPassword) setCachedPassword(sudoPassword);
|
|
341
345
|
return { running: true, pid: savedPid };
|
|
@@ -357,7 +361,7 @@ async function startServer(apiKey, sudoPassword) {
|
|
|
357
361
|
if (portStatus === "in-use" || portStatus === "no-permission") {
|
|
358
362
|
const owner = await getPort443Owner(sudoPassword);
|
|
359
363
|
if (owner && owner.name === "node") {
|
|
360
|
-
|
|
364
|
+
log(`Killing orphan node process on port 443 (PID ${owner.pid})...`);
|
|
361
365
|
try {
|
|
362
366
|
const { execWithPassword } = require("./dns/dnsConfig");
|
|
363
367
|
await execWithPassword(`kill -9 ${owner.pid}`, sudoPassword);
|
|
@@ -372,12 +376,19 @@ async function startServer(apiKey, sudoPassword) {
|
|
|
372
376
|
}
|
|
373
377
|
}
|
|
374
378
|
|
|
375
|
-
// Step 1:
|
|
379
|
+
// Step 1: Generate Root CA if missing or expired
|
|
376
380
|
const rootCACertPath = path.join(MITM_DIR, "rootCA.crt");
|
|
377
381
|
const rootCAKeyPath = path.join(MITM_DIR, "rootCA.key");
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
382
|
+
const certExists = fs.existsSync(rootCACertPath) && fs.existsSync(rootCAKeyPath);
|
|
383
|
+
|
|
384
|
+
if (!certExists || isCertExpired(rootCACertPath)) {
|
|
385
|
+
if (certExists) {
|
|
386
|
+
// Uninstall expired cert from system store before regenerating
|
|
387
|
+
log("🔐 Cert expired — uninstalling old cert...");
|
|
388
|
+
const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
|
|
389
|
+
try { await uninstallCert(password, rootCACertPath); } catch { /* best effort */ }
|
|
390
|
+
}
|
|
391
|
+
log("🔐 Generating Root CA...");
|
|
381
392
|
await generateCert();
|
|
382
393
|
}
|
|
383
394
|
|
|
@@ -385,35 +396,42 @@ async function startServer(apiKey, sudoPassword) {
|
|
|
385
396
|
const { checkCertInstalled } = require("./cert/install");
|
|
386
397
|
const rootCATrusted = await checkCertInstalled(rootCACertPath);
|
|
387
398
|
if (!rootCATrusted) {
|
|
388
|
-
|
|
389
|
-
// Use provided password or cached/stored password
|
|
399
|
+
log("🔐 Cert: not trusted → installing...");
|
|
390
400
|
const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
|
|
391
401
|
if (!password && !IS_WIN) {
|
|
392
402
|
throw new Error("Sudo password required to install Root CA certificate");
|
|
393
403
|
}
|
|
394
|
-
|
|
395
|
-
|
|
404
|
+
try {
|
|
405
|
+
await installCert(password, rootCACertPath);
|
|
406
|
+
log("🔐 Cert: ✅ trusted");
|
|
407
|
+
} catch (e) {
|
|
408
|
+
throw new Error(`Failed to trust certificate: ${e.message}`);
|
|
409
|
+
}
|
|
410
|
+
} else {
|
|
411
|
+
log("🔐 Cert: already trusted ✅");
|
|
396
412
|
}
|
|
397
413
|
|
|
398
414
|
// Step 2: Spawn server (Root CA already installed in Step 1.5)
|
|
415
|
+
log("🚀 Starting server...");
|
|
399
416
|
if (IS_WIN) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
+
// Kill any process using port 443 before spawning
|
|
418
|
+
try {
|
|
419
|
+
const psKill = `$c = Get-NetTCPConnection -LocalPort 443 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1; if ($c -and $c.OwningProcess -gt 4) { Stop-Process -Id $c.OwningProcess -Force -ErrorAction SilentlyContinue }`;
|
|
420
|
+
execSync(`powershell -NonInteractive -WindowStyle Hidden -Command "${psKill}"`, { windowsHide: true });
|
|
421
|
+
await new Promise(r => setTimeout(r, 500));
|
|
422
|
+
} catch { /* best effort */ }
|
|
423
|
+
|
|
424
|
+
// Spawn directly — process already has admin rights
|
|
425
|
+
serverProcess = spawn(
|
|
426
|
+
process.execPath,
|
|
427
|
+
[SERVER_PATH],
|
|
428
|
+
{
|
|
429
|
+
detached: false,
|
|
430
|
+
windowsHide: true,
|
|
431
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
432
|
+
env: { ...process.env, ROUTER_API_KEY: apiKey, NODE_ENV: "production" },
|
|
433
|
+
}
|
|
434
|
+
);
|
|
417
435
|
|
|
418
436
|
if (_updateSettings) await _updateSettings({ mitmCertInstalled: true }).catch(() => { });
|
|
419
437
|
} else {
|
|
@@ -427,26 +445,28 @@ async function startServer(apiKey, sudoPassword) {
|
|
|
427
445
|
serverProcess.stdin.end();
|
|
428
446
|
}
|
|
429
447
|
|
|
430
|
-
if (
|
|
448
|
+
if (serverProcess) {
|
|
431
449
|
serverPid = serverProcess.pid;
|
|
432
450
|
fs.writeFileSync(PID_FILE, String(serverPid));
|
|
433
451
|
mitmLastStartTime = Date.now();
|
|
434
452
|
}
|
|
435
453
|
|
|
436
454
|
let startError = null;
|
|
437
|
-
if (
|
|
455
|
+
if (serverProcess) {
|
|
438
456
|
serverProcess.stdout.on("data", (data) => {
|
|
439
|
-
|
|
457
|
+
// server.js already formats its own logs — print as-is
|
|
458
|
+
process.stdout.write(data);
|
|
440
459
|
});
|
|
441
460
|
serverProcess.stderr.on("data", (data) => {
|
|
442
461
|
const msg = data.toString().trim();
|
|
443
|
-
|
|
444
|
-
|
|
462
|
+
// Mac/Linux: filter sudo password prompt noise
|
|
463
|
+
if (msg && (IS_WIN || (!msg.includes("Password:") && !msg.includes("password for")))) {
|
|
464
|
+
err(msg);
|
|
445
465
|
startError = msg;
|
|
446
466
|
}
|
|
447
467
|
});
|
|
448
468
|
serverProcess.on("exit", (code) => {
|
|
449
|
-
|
|
469
|
+
log(`Server exited (code: ${code})`);
|
|
450
470
|
serverProcess = null;
|
|
451
471
|
serverPid = null;
|
|
452
472
|
try { fs.unlinkSync(PID_FILE); } catch { /* ignore */ }
|
|
@@ -455,19 +475,23 @@ async function startServer(apiKey, sudoPassword) {
|
|
|
455
475
|
});
|
|
456
476
|
}
|
|
457
477
|
|
|
458
|
-
const health = await pollMitmHealth(
|
|
478
|
+
const health = await pollMitmHealth(8000, MITM_PORT);
|
|
459
479
|
if (!health) {
|
|
460
|
-
if (
|
|
480
|
+
if (serverProcess && !serverProcess.killed) { try { serverProcess.kill(); } catch { /* ignore */ } serverProcess = null; }
|
|
461
481
|
const processUsing443 = getProcessUsingPort443();
|
|
462
482
|
const portInfo = processUsing443 ? ` Port 443 already in use by ${processUsing443}.` : "";
|
|
463
483
|
const reason = startError || `Check sudo password or port 443 access.${portInfo}`;
|
|
464
484
|
throw new Error(`MITM server failed to start. ${reason}`);
|
|
465
485
|
}
|
|
466
486
|
|
|
467
|
-
if (
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
487
|
+
if (_updateSettings) await _updateSettings({ mitmCertInstalled: true }).catch(() => { });
|
|
488
|
+
|
|
489
|
+
log(`✅ Server healthy (PID: ${serverPid || health.pid})`);
|
|
490
|
+
|
|
491
|
+
// Log DNS status per tool
|
|
492
|
+
const dnsStatus = checkAllDNSStatus();
|
|
493
|
+
for (const [tool, active] of Object.entries(dnsStatus)) {
|
|
494
|
+
log(`🌐 DNS ${tool}: ${active ? "✅ active" : "❌ inactive"}`);
|
|
471
495
|
}
|
|
472
496
|
|
|
473
497
|
await saveMitmSettings(true, sudoPassword);
|
|
@@ -483,7 +507,7 @@ async function stopServer(sudoPassword) {
|
|
|
483
507
|
// Prevent auto-restart from triggering on intentional stop
|
|
484
508
|
mitmIsRestarting = true;
|
|
485
509
|
mitmRestartCount = 0;
|
|
486
|
-
|
|
510
|
+
log("⏹ Stopping server...");
|
|
487
511
|
|
|
488
512
|
// Kill server process
|
|
489
513
|
const proc = serverProcess;
|
|
@@ -492,7 +516,7 @@ async function stopServer(sudoPassword) {
|
|
|
492
516
|
: (() => { try { return parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10); } catch { return null; } })();
|
|
493
517
|
|
|
494
518
|
if (pidToKill && isProcessAlive(pidToKill)) {
|
|
495
|
-
|
|
519
|
+
log(`Killing server (PID: ${pidToKill})...`);
|
|
496
520
|
killProcess(pidToKill, false, sudoPassword);
|
|
497
521
|
await new Promise(r => setTimeout(r, 1000));
|
|
498
522
|
if (isProcessAlive(pidToKill)) killProcess(pidToKill, true, sudoPassword);
|
|
@@ -501,33 +525,15 @@ async function stopServer(sudoPassword) {
|
|
|
501
525
|
serverPid = null;
|
|
502
526
|
|
|
503
527
|
if (IS_WIN) {
|
|
504
|
-
//
|
|
528
|
+
// Process already has admin rights — edit hosts file directly
|
|
505
529
|
const hostsFile = path.join(process.env.SystemRoot || "C:\\Windows", "System32", "drivers", "etc", "hosts");
|
|
506
|
-
const psSQ = (s) => s.replace(/'/g, "''");
|
|
507
530
|
const allHosts = Object.values(TOOL_HOSTS).flat();
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
.
|
|
513
|
-
|
|
514
|
-
const tmpHosts = path.join(os.tmpdir(), `mitm_hosts_clean_${Date.now()}.tmp`);
|
|
515
|
-
fs.writeFileSync(tmpHosts, filtered, "utf8");
|
|
516
|
-
|
|
517
|
-
const psScript = [
|
|
518
|
-
`$ErrorActionPreference = 'Stop'`,
|
|
519
|
-
`try {`,
|
|
520
|
-
` Copy-Item -Path '${psSQ(tmpHosts)}' -Destination '${psSQ(hostsFile)}' -Force -ErrorAction Stop`,
|
|
521
|
-
` ipconfig /flushdns | Out-Null`,
|
|
522
|
-
` Remove-Item '${psSQ(tmpHosts)}' -ErrorAction SilentlyContinue`,
|
|
523
|
-
`} catch {`,
|
|
524
|
-
` Remove-Item '${psSQ(tmpHosts)}' -ErrorAction SilentlyContinue`,
|
|
525
|
-
`}`,
|
|
526
|
-
].join("\n");
|
|
527
|
-
|
|
528
|
-
const tmpPs1 = path.join(os.tmpdir(), `mitm_stop_${Date.now()}.ps1`);
|
|
529
|
-
fs.writeFileSync(tmpPs1, psScript, "utf8");
|
|
530
|
-
await executeElevatedPowerShell(tmpPs1, 30000);
|
|
531
|
+
try {
|
|
532
|
+
const hostsContent = fs.readFileSync(hostsFile, "utf8");
|
|
533
|
+
const filtered = hostsContent.split(/\r?\n/).filter(l => !allHosts.some(h => l.includes(h))).join("\r\n");
|
|
534
|
+
fs.writeFileSync(hostsFile, filtered, "utf8");
|
|
535
|
+
require("child_process").execSync("ipconfig /flushdns", { windowsHide: true });
|
|
536
|
+
} catch (e) { err(`Failed to clean hosts: ${e.message}`); }
|
|
531
537
|
} else {
|
|
532
538
|
await removeAllDNSEntries(sudoPassword);
|
|
533
539
|
}
|
|
@@ -562,6 +568,19 @@ async function disableToolDNS(tool, sudoPassword) {
|
|
|
562
568
|
return { success: true };
|
|
563
569
|
}
|
|
564
570
|
|
|
571
|
+
/**
|
|
572
|
+
* Install Root CA to system trust store (standalone, no server start)
|
|
573
|
+
*/
|
|
574
|
+
async function trustCert(sudoPassword) {
|
|
575
|
+
const rootCACertPath = path.join(MITM_DIR, "rootCA.crt");
|
|
576
|
+
if (!fs.existsSync(rootCACertPath)) throw new Error("Root CA not found. Start server first to generate it.");
|
|
577
|
+
const { installCert } = require("./cert/install");
|
|
578
|
+
const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
|
|
579
|
+
if (!password && !IS_WIN) throw new Error("Sudo password required to trust certificate");
|
|
580
|
+
await installCert(password, rootCACertPath);
|
|
581
|
+
if (password) setCachedPassword(password);
|
|
582
|
+
}
|
|
583
|
+
|
|
565
584
|
// Legacy aliases for backward compatibility
|
|
566
585
|
const startMitm = startServer;
|
|
567
586
|
const stopMitm = stopServer;
|
|
@@ -572,6 +591,7 @@ module.exports = {
|
|
|
572
591
|
stopServer,
|
|
573
592
|
enableToolDNS,
|
|
574
593
|
disableToolDNS,
|
|
594
|
+
trustCert,
|
|
575
595
|
// Legacy
|
|
576
596
|
startMitm,
|
|
577
597
|
stopMitm,
|
package/app/src/mitm/server.js
CHANGED
|
@@ -3,6 +3,7 @@ const fs = require("fs");
|
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const dns = require("dns");
|
|
5
5
|
const { promisify } = require("util");
|
|
6
|
+
const { log, err } = require("./logger");
|
|
6
7
|
|
|
7
8
|
// Allow self-signed certs from MITM root CA when fetching external hosts
|
|
8
9
|
|
|
@@ -25,7 +26,7 @@ const DB_FILE = path.join(DATA_DIR, "db.json");
|
|
|
25
26
|
const ENABLE_FILE_LOG = false;
|
|
26
27
|
|
|
27
28
|
if (!API_KEY) {
|
|
28
|
-
|
|
29
|
+
err("ROUTER_API_KEY required");
|
|
29
30
|
process.exit(1);
|
|
30
31
|
}
|
|
31
32
|
|
|
@@ -57,11 +58,11 @@ function sniCallback(servername, cb) {
|
|
|
57
58
|
|
|
58
59
|
// Cache it
|
|
59
60
|
certCache.set(servername, ctx);
|
|
60
|
-
|
|
61
|
+
log(`🔐 Cert generated: ${servername}`);
|
|
61
62
|
|
|
62
63
|
cb(null, ctx);
|
|
63
64
|
} catch (error) {
|
|
64
|
-
|
|
65
|
+
err(`SNI error for ${servername}: ${error.message}`);
|
|
65
66
|
cb(error);
|
|
66
67
|
}
|
|
67
68
|
}
|
|
@@ -79,7 +80,7 @@ try {
|
|
|
79
80
|
SNICallback: sniCallback
|
|
80
81
|
};
|
|
81
82
|
} catch (e) {
|
|
82
|
-
|
|
83
|
+
err(`Root CA not found in ${certDir}: ${e.message}`);
|
|
83
84
|
process.exit(1);
|
|
84
85
|
}
|
|
85
86
|
|
|
@@ -134,7 +135,13 @@ function getMappedModel(tool, model) {
|
|
|
134
135
|
try {
|
|
135
136
|
if (!fs.existsSync(DB_FILE)) return null;
|
|
136
137
|
const db = JSON.parse(fs.readFileSync(DB_FILE, "utf-8"));
|
|
137
|
-
|
|
138
|
+
const aliases = db.mitmAlias?.[tool];
|
|
139
|
+
if (!aliases) return null;
|
|
140
|
+
// Exact match first
|
|
141
|
+
if (aliases[model]) return aliases[model];
|
|
142
|
+
// Prefix match fallback: find alias key that starts with model or model starts with key
|
|
143
|
+
const prefixKey = Object.keys(aliases).find(k => k && aliases[k] && (model.startsWith(k) || k.startsWith(model)));
|
|
144
|
+
return prefixKey ? aliases[prefixKey] : null;
|
|
138
145
|
} catch {
|
|
139
146
|
return null;
|
|
140
147
|
}
|
|
@@ -167,8 +174,8 @@ async function passthrough(req, res, bodyBuffer) {
|
|
|
167
174
|
forwardRes.pipe(res);
|
|
168
175
|
});
|
|
169
176
|
|
|
170
|
-
forwardReq.on("error", (
|
|
171
|
-
|
|
177
|
+
forwardReq.on("error", (e) => {
|
|
178
|
+
err(`Passthrough error: ${e.message}`);
|
|
172
179
|
if (!res.headersSent) res.writeHead(502);
|
|
173
180
|
res.end("Bad Gateway");
|
|
174
181
|
});
|
|
@@ -216,7 +223,7 @@ async function intercept(req, res, bodyBuffer, mappedModel) {
|
|
|
216
223
|
res.write(decoder.decode(value, { stream: true }));
|
|
217
224
|
}
|
|
218
225
|
} catch (error) {
|
|
219
|
-
|
|
226
|
+
err(`Intercept error: ${error.message}`);
|
|
220
227
|
if (!res.headersSent) res.writeHead(500, { "Content-Type": "application/json" });
|
|
221
228
|
res.end(JSON.stringify({ error: { message: error.message, type: "mitm_error" } }));
|
|
222
229
|
}
|
|
@@ -250,30 +257,34 @@ const server = https.createServer(sslOptions, async (req, res) => {
|
|
|
250
257
|
if (!isChat) return passthrough(req, res, bodyBuffer);
|
|
251
258
|
|
|
252
259
|
const model = extractModel(req.url, bodyBuffer);
|
|
253
|
-
|
|
260
|
+
log(`🔍 model="${model}" url=${req.url}`);
|
|
254
261
|
const mappedModel = getMappedModel(tool, model);
|
|
255
262
|
|
|
256
|
-
if (!mappedModel)
|
|
263
|
+
if (!mappedModel) {
|
|
264
|
+
log(`⏩ passthrough | no mapping | ${tool} | ${model || "unknown"}`);
|
|
265
|
+
return passthrough(req, res, bodyBuffer);
|
|
266
|
+
}
|
|
257
267
|
|
|
268
|
+
log(`⚡ intercept | ${tool} | ${model} → ${mappedModel}`);
|
|
258
269
|
return intercept(req, res, bodyBuffer, mappedModel);
|
|
259
|
-
} catch (
|
|
260
|
-
|
|
270
|
+
} catch (e) {
|
|
271
|
+
err(`Unhandled request error: ${e.message}`);
|
|
261
272
|
if (!res.headersSent) res.writeHead(500, { "Content-Type": "application/json" });
|
|
262
|
-
res.end(JSON.stringify({ error: { message:
|
|
273
|
+
res.end(JSON.stringify({ error: { message: e.message, type: "mitm_error" } }));
|
|
263
274
|
}
|
|
264
275
|
});
|
|
265
276
|
|
|
266
277
|
server.listen(LOCAL_PORT, () => {
|
|
267
|
-
|
|
278
|
+
log(`🚀 Server ready on :${LOCAL_PORT}`);
|
|
268
279
|
});
|
|
269
280
|
|
|
270
281
|
server.on("error", (error) => {
|
|
271
282
|
if (error.code === "EADDRINUSE") {
|
|
272
|
-
|
|
283
|
+
err(`Port ${LOCAL_PORT} already in use`);
|
|
273
284
|
} else if (error.code === "EACCES") {
|
|
274
|
-
|
|
285
|
+
err(`Permission denied for port ${LOCAL_PORT}`);
|
|
275
286
|
} else {
|
|
276
|
-
|
|
287
|
+
err(error.message);
|
|
277
288
|
}
|
|
278
289
|
process.exit(1);
|
|
279
290
|
});
|
package/cli.js
CHANGED
|
@@ -121,22 +121,20 @@ function killAllAppProcesses() {
|
|
|
121
121
|
let pids = [];
|
|
122
122
|
|
|
123
123
|
if (platform === "win32") {
|
|
124
|
-
// Windows: use
|
|
124
|
+
// Windows: use WMI to get full CommandLine (tasklist /V doesn't include it)
|
|
125
125
|
try {
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
const psCmd = `powershell -NonInteractive -WindowStyle Hidden -Command "Get-WmiObject Win32_Process -Filter 'Name=\\"node.exe\\"' | Select-Object ProcessId,CommandLine | ConvertTo-Csv -NoTypeInformation"`;
|
|
127
|
+
const output = execSync(psCmd, {
|
|
128
|
+
encoding: "utf8",
|
|
129
129
|
windowsHide: true,
|
|
130
130
|
timeout: 5000
|
|
131
131
|
});
|
|
132
|
-
const lines = output.split(
|
|
133
|
-
|
|
132
|
+
const lines = output.split("\n").slice(1).filter(l => l.trim());
|
|
134
133
|
lines.forEach(line => {
|
|
135
134
|
const isAppProcess = line.toLowerCase().includes("9router") ||
|
|
136
135
|
line.toLowerCase().includes("next-server");
|
|
137
136
|
if (isAppProcess) {
|
|
138
|
-
|
|
139
|
-
const match = line.match(/"node\.exe","(\d+)"/i);
|
|
137
|
+
const match = line.match(/^"(\d+)"/);
|
|
140
138
|
if (match && match[1] && match[1] !== process.pid.toString()) {
|
|
141
139
|
pids.push(match[1]);
|
|
142
140
|
}
|