Showing preview only (2,676K chars total). Download the full file or copy to clipboard to get everything.
Repository: wanghongenpin/proxypin
Branch: main
Commit: 8ab517bb3835
Files: 435
Total size: 2.5 MB
Directory structure:
gitextract_xlm06j4i/
├── .github/
│ └── ISSUE_TEMPLATE/
│ ├── bug_report.yml
│ ├── feature_request.yml
│ └── 功能请求.yml
├── .gitignore
├── .metadata
├── LICENSE
├── README.md
├── README_CN.md
├── analysis_options.yaml
├── android/
│ ├── .gitignore
│ ├── app/
│ │ ├── build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ ├── debug/
│ │ │ └── AndroidManifest.xml
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin/
│ │ │ │ └── com/
│ │ │ │ └── network/
│ │ │ │ └── proxy/
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── ProxyVpnService.kt
│ │ │ │ ├── VpnAlertDialog.kt
│ │ │ │ ├── plugin/
│ │ │ │ │ ├── AndroidFlutterPlugin.kt
│ │ │ │ │ ├── AppInfo.kt
│ │ │ │ │ ├── AppLifecyclePlugin.kt
│ │ │ │ │ ├── InstalledAppsPlugin.kt
│ │ │ │ │ ├── PictureInPicturePlugin.kt
│ │ │ │ │ ├── ProcessInfoPlugin.kt
│ │ │ │ │ └── VpnServicePlugin.kt
│ │ │ │ └── vpn/
│ │ │ │ ├── Connection.kt
│ │ │ │ ├── ConnectionHandler.kt
│ │ │ │ ├── ConnectionManager.kt
│ │ │ │ ├── Protocol.java
│ │ │ │ ├── ProxyVpnThread.kt
│ │ │ │ ├── Tag.kt
│ │ │ │ ├── socket/
│ │ │ │ │ ├── ClientPacketWriter.kt
│ │ │ │ │ ├── CloseableConnection.kt
│ │ │ │ │ ├── Constant.kt
│ │ │ │ │ ├── ProtectSocket.kt
│ │ │ │ │ ├── ProtectSocketHolder.kt
│ │ │ │ │ ├── SocketChannelReader.java
│ │ │ │ │ ├── SocketChannelWriter.java
│ │ │ │ │ └── SocketNIODataService.java
│ │ │ │ ├── transport/
│ │ │ │ │ ├── Packet.kt
│ │ │ │ │ ├── icmp/
│ │ │ │ │ │ ├── ICMPPacket.java
│ │ │ │ │ │ └── ICMPPacketFactory.java
│ │ │ │ │ └── protocol/
│ │ │ │ │ ├── IP4Header.kt
│ │ │ │ │ ├── TCPHeader.kt
│ │ │ │ │ ├── TCPPacketFactory.kt
│ │ │ │ │ ├── TransportHeader.kt
│ │ │ │ │ └── UDPHeader.kt
│ │ │ │ └── util/
│ │ │ │ ├── PacketUtil.kt
│ │ │ │ ├── ProcessInfoManager.kt
│ │ │ │ ├── SimpleCache.kt
│ │ │ │ └── TLS.kt
│ │ │ └── res/
│ │ │ ├── drawable/
│ │ │ │ └── launch_background.xml
│ │ │ ├── drawable-v21/
│ │ │ │ └── launch_background.xml
│ │ │ ├── mipmap-anydpi-v26/
│ │ │ │ └── ic_launcher.xml
│ │ │ ├── values/
│ │ │ │ └── styles.xml
│ │ │ └── values-night/
│ │ │ └── styles.xml
│ │ └── profile/
│ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ └── settings.gradle
├── assets/
│ ├── certs/
│ │ ├── ca.crt
│ │ ├── ca_key.pem
│ │ └── ca_private.der
│ └── js/
│ └── fetch.js
├── devtools_options.yaml
├── distribute_options.yaml
├── ios/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Podfile
│ ├── ProxyPin/
│ │ ├── Info.plist
│ │ ├── PacketTunnelProvider.swift
│ │ ├── ProxyPin-Bridging-Header.h
│ │ ├── ProxyPin.entitlements
│ │ └── vpn/
│ │ ├── Connection.swift
│ │ ├── ConnectionHandler.swift
│ │ ├── ConnectionManager.swift
│ │ ├── NWProtocol.swift
│ │ ├── ProxyVpnService.swift
│ │ ├── QueueFactory.swift
│ │ ├── ping/
│ │ │ ├── GBPing.h
│ │ │ ├── GBPing.m
│ │ │ ├── GBPingHelper.swift
│ │ │ ├── GBPingSummary.h
│ │ │ ├── GBPingSummary.m
│ │ │ └── ICMPHeader.h
│ │ ├── socket/
│ │ │ ├── ClientPacketWriter.swift
│ │ │ ├── CloseableConnection.swift
│ │ │ └── SocketIOService.swift
│ │ ├── transport/
│ │ │ ├── Packet.swift
│ │ │ └── protocol/
│ │ │ ├── ICMPPacket.swift
│ │ │ ├── IP4Header.swift
│ │ │ ├── TCPHeader.swift
│ │ │ ├── TCPPacketFactory.swift
│ │ │ ├── TransportHeader.swift
│ │ │ └── UDPHeader.swift
│ │ └── utils/
│ │ ├── PacketUtil.swift
│ │ └── TLS.swift
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── LaunchImage.imageset/
│ │ │ ├── Contents.json
│ │ │ └── README.md
│ │ ├── AudioManager.swift
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Handlers/
│ │ │ └── MethodHandler.swift
│ │ ├── Info.plist
│ │ ├── Runner-Bridging-Header.h
│ │ ├── Runner.entitlements
│ │ ├── VpnManager.swift
│ │ ├── en.lproj/
│ │ │ └── InfoPlist.strings
│ │ ├── pip/
│ │ │ ├── PictureInPictureManager.swift
│ │ │ └── PictureInPictureView.swift
│ │ └── zh-Hans.lproj/
│ │ ├── InfoPlist.strings
│ │ ├── LaunchScreen.strings
│ │ └── Main.strings
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
│ └── RunnerTests/
│ └── RunnerTests.swift
├── l10n.yaml
├── lib/
│ ├── l10n/
│ │ ├── app_en.arb
│ │ ├── app_localizations.dart
│ │ ├── app_localizations_en.dart
│ │ ├── app_localizations_zh.dart
│ │ ├── app_zh.arb
│ │ └── app_zh_Hant.arb
│ ├── main.dart
│ ├── native/
│ │ ├── app_lifecycle.dart
│ │ ├── installed_apps.dart
│ │ ├── native_method.dart
│ │ ├── pip.dart
│ │ ├── process_info.dart
│ │ └── vpn.dart
│ ├── network/
│ │ ├── bin/
│ │ │ ├── configuration.dart
│ │ │ ├── listener.dart
│ │ │ └── server.dart
│ │ ├── channel/
│ │ │ ├── channel.dart
│ │ │ ├── channel_context.dart
│ │ │ ├── channel_dispatcher.dart
│ │ │ ├── host_port.dart
│ │ │ └── network.dart
│ │ ├── components/
│ │ │ ├── host_filter.dart
│ │ │ ├── hosts.dart
│ │ │ ├── interceptor.dart
│ │ │ ├── js/
│ │ │ │ ├── file.dart
│ │ │ │ ├── md5.dart
│ │ │ │ ├── script_engine.dart
│ │ │ │ └── xhr.dart
│ │ │ ├── manager/
│ │ │ │ ├── hosts_manager.dart
│ │ │ │ ├── report_server_manager.dart
│ │ │ │ ├── request_block_manager.dart
│ │ │ │ ├── request_breakpoint_manager.dart
│ │ │ │ ├── request_crypto_manager.dart
│ │ │ │ ├── request_map_manager.dart
│ │ │ │ ├── request_rewrite_manager.dart
│ │ │ │ ├── rewrite_rule.dart
│ │ │ │ └── script_manager.dart
│ │ │ ├── report_server_interceptor.dart
│ │ │ ├── request_block.dart
│ │ │ ├── request_breakpoint.dart
│ │ │ ├── request_map.dart
│ │ │ ├── request_rewrite.dart
│ │ │ └── script.dart
│ │ ├── handle/
│ │ │ ├── http_proxy_handle.dart
│ │ │ ├── relay_handle.dart
│ │ │ ├── sse_handle.dart
│ │ │ └── websocket_handle.dart
│ │ ├── http/
│ │ │ ├── codec.dart
│ │ │ ├── constants.dart
│ │ │ ├── content_type.dart
│ │ │ ├── h2/
│ │ │ │ ├── frame.dart
│ │ │ │ ├── h2_codec.dart
│ │ │ │ ├── hpack/
│ │ │ │ │ ├── hpack.dart
│ │ │ │ │ ├── huffman.dart
│ │ │ │ │ └── huffman_table.dart
│ │ │ │ └── setting.dart
│ │ │ ├── http.dart
│ │ │ ├── http_client.dart
│ │ │ ├── http_headers.dart
│ │ │ ├── parse/
│ │ │ │ ├── body_reader.dart
│ │ │ │ └── http_parser.dart
│ │ │ ├── sse.dart
│ │ │ └── websocket.dart
│ │ ├── socks/
│ │ │ └── socks5.dart
│ │ └── util/
│ │ ├── attribute_keys.dart
│ │ ├── byte_buf.dart
│ │ ├── byte_utils.dart
│ │ ├── cache.dart
│ │ ├── cert/
│ │ │ ├── basic_constraints.dart
│ │ │ ├── cert_data.dart
│ │ │ ├── der.dart
│ │ │ ├── extension.dart
│ │ │ ├── key_usage.dart
│ │ │ ├── pkcs12.dart
│ │ │ └── x509.dart
│ │ ├── compress.dart
│ │ ├── crts.dart
│ │ ├── crypto.dart
│ │ ├── file_read.dart
│ │ ├── lang.dart
│ │ ├── localizations.dart
│ │ ├── logger.dart
│ │ ├── process_info.dart
│ │ ├── proxy_helper.dart
│ │ ├── random.dart
│ │ ├── socket_address.dart
│ │ ├── system_proxy.dart
│ │ ├── task_queue.dart
│ │ ├── tls.dart
│ │ └── uri.dart
│ ├── storage/
│ │ ├── favorites.dart
│ │ ├── histories.dart
│ │ ├── local_storage.dart
│ │ ├── path.dart
│ │ └── shared_preference_keys.dart
│ ├── ui/
│ │ ├── app_update/
│ │ │ ├── app_update_repository.dart
│ │ │ ├── constants.dart
│ │ │ ├── new_version_dialog.dart
│ │ │ └── remote_version_entity.dart
│ │ ├── component/
│ │ │ ├── app_dialog.dart
│ │ │ ├── buttons.dart
│ │ │ ├── chinese_font.dart
│ │ │ ├── context_menu_region.dart
│ │ │ ├── device.dart
│ │ │ ├── history_cache_time.dart
│ │ │ ├── http_method_popup.dart
│ │ │ ├── json/
│ │ │ │ ├── json_text.dart
│ │ │ │ ├── json_viewer.dart
│ │ │ │ ├── theme.dart
│ │ │ │ └── toast.dart
│ │ │ ├── memory_cleanup.dart
│ │ │ ├── model/
│ │ │ │ └── search_model.dart
│ │ │ ├── multi_window.dart
│ │ │ ├── proxy_port_setting.dart
│ │ │ ├── qrcode/
│ │ │ │ └── qr_scan_view.dart
│ │ │ ├── search/
│ │ │ │ ├── highlight_text.dart
│ │ │ │ ├── search_controller.dart
│ │ │ │ └── search_field.dart
│ │ │ ├── search_condition.dart
│ │ │ ├── split_view.dart
│ │ │ ├── state_component.dart
│ │ │ ├── text_field.dart
│ │ │ ├── transition.dart
│ │ │ ├── utils.dart
│ │ │ └── widgets.dart
│ │ ├── configuration.dart
│ │ ├── content/
│ │ │ ├── body.dart
│ │ │ ├── headers.dart
│ │ │ ├── menu.dart
│ │ │ ├── panel.dart
│ │ │ └── web_socket.dart
│ │ ├── desktop/
│ │ │ ├── common.dart
│ │ │ ├── debug/
│ │ │ │ └── breakpoint_executor.dart
│ │ │ ├── desktop.dart
│ │ │ ├── left_menus/
│ │ │ │ ├── favorite.dart
│ │ │ │ ├── history.dart
│ │ │ │ └── navigation.dart
│ │ │ ├── preference.dart
│ │ │ ├── request/
│ │ │ │ ├── domians.dart
│ │ │ │ ├── list.dart
│ │ │ │ ├── repeat.dart
│ │ │ │ ├── report_servers.dart
│ │ │ │ ├── request.dart
│ │ │ │ ├── request_editor.dart
│ │ │ │ ├── request_sequence.dart
│ │ │ │ └── search.dart
│ │ │ ├── setting/
│ │ │ │ ├── about.dart
│ │ │ │ ├── external_proxy.dart
│ │ │ │ ├── filter.dart
│ │ │ │ ├── hosts.dart
│ │ │ │ ├── request_block.dart
│ │ │ │ ├── request_breakpoint.dart
│ │ │ │ ├── request_crypto.dart
│ │ │ │ ├── request_map/
│ │ │ │ │ ├── map_local.dart
│ │ │ │ │ └── map_scipt.dart
│ │ │ │ ├── request_map.dart
│ │ │ │ ├── request_rewrite.dart
│ │ │ │ ├── rewrite/
│ │ │ │ │ ├── rewrite_replace.dart
│ │ │ │ │ └── rewrite_update.dart
│ │ │ │ ├── script.dart
│ │ │ │ └── setting.dart
│ │ │ ├── ssl/
│ │ │ │ ├── cert_installer.dart
│ │ │ │ ├── pc_cert.dart
│ │ │ │ └── ssl.dart
│ │ │ ├── toolbar/
│ │ │ │ ├── phone_connect.dart
│ │ │ │ └── toolbar.dart
│ │ │ ├── widgets/
│ │ │ │ ├── highlight.dart
│ │ │ │ └── windows_toolbar.dart
│ │ │ └── window_listener.dart
│ │ ├── launch/
│ │ │ └── launch.dart
│ │ ├── mobile/
│ │ │ ├── debug/
│ │ │ │ └── breakpoint_executor.dart
│ │ │ ├── menu/
│ │ │ │ ├── bottom_navigation.dart
│ │ │ │ ├── drawer.dart
│ │ │ │ └── menu.dart
│ │ │ ├── mobile.dart
│ │ │ ├── request/
│ │ │ │ ├── domians.dart
│ │ │ │ ├── favorite.dart
│ │ │ │ ├── history.dart
│ │ │ │ ├── list.dart
│ │ │ │ ├── repeat.dart
│ │ │ │ ├── request.dart
│ │ │ │ ├── request_editor.dart
│ │ │ │ ├── request_editor_source.dart
│ │ │ │ ├── request_sequence.dart
│ │ │ │ └── search.dart
│ │ │ ├── setting/
│ │ │ │ ├── app_filter.dart
│ │ │ │ ├── filter.dart
│ │ │ │ ├── hosts.dart
│ │ │ │ ├── preference.dart
│ │ │ │ ├── proxy.dart
│ │ │ │ ├── report_servers.dart
│ │ │ │ ├── request_block.dart
│ │ │ │ ├── request_breakpoint.dart
│ │ │ │ ├── request_crypto.dart
│ │ │ │ ├── request_map/
│ │ │ │ │ ├── map_local.dart
│ │ │ │ │ └── map_scipt.dart
│ │ │ │ ├── request_map.dart
│ │ │ │ ├── request_rewrite.dart
│ │ │ │ ├── rewrite/
│ │ │ │ │ ├── rewrite_replace.dart
│ │ │ │ │ └── rewrite_update.dart
│ │ │ │ ├── script.dart
│ │ │ │ ├── ssl.dart
│ │ │ │ ├── theme.dart
│ │ │ │ └── video_player.dart
│ │ │ └── widgets/
│ │ │ ├── about.dart
│ │ │ ├── floating_window.dart
│ │ │ ├── highlight.dart
│ │ │ ├── pip.dart
│ │ │ └── remote_device.dart
│ │ └── toolbox/
│ │ ├── aes_page.dart
│ │ ├── cert_hash.dart
│ │ ├── encoder.dart
│ │ ├── js_run.dart
│ │ ├── qr_code_page.dart
│ │ ├── regexp.dart
│ │ ├── timestamp.dart
│ │ ├── toolbox.dart
│ │ └── websocket_request.dart
│ └── utils/
│ ├── aes.dart
│ ├── crypto_body_decoder.dart
│ ├── curl.dart
│ ├── desktop_support.dart
│ ├── export_request.dart
│ ├── files.dart
│ ├── font.dart
│ ├── har.dart
│ ├── ip.dart
│ ├── keyword_highlight.dart
│ ├── lang.dart
│ ├── listenable_list.dart
│ ├── navigator.dart
│ ├── num.dart
│ ├── platform.dart
│ ├── python.dart
│ └── task.dart
├── linux/
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── build.sh
│ ├── flutter/
│ │ ├── CMakeLists.txt
│ │ ├── generated_plugin_registrant.cc
│ │ ├── generated_plugin_registrant.h
│ │ └── generated_plugins.cmake
│ ├── main.cc
│ ├── my_application.cc
│ ├── my_application.h
│ └── proxy-pin.desktop
├── macos/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── Flutter-Debug.xcconfig
│ │ ├── Flutter-Release.xcconfig
│ │ └── GeneratedPluginRegistrant.swift
│ ├── Podfile
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── AppLifecycleChannel.swift
│ │ ├── Assets.xcassets/
│ │ │ └── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── MainMenu.xib
│ │ ├── Configs/
│ │ │ ├── AppInfo.xcconfig
│ │ │ ├── Debug.xcconfig
│ │ │ ├── Release.xcconfig
│ │ │ └── Warnings.xcconfig
│ │ ├── DebugProfile.entitlements
│ │ ├── Info.plist
│ │ ├── MainFlutterWindow.swift
│ │ ├── Release.entitlements
│ │ └── RunnerProfile.entitlements
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ ├── RunnerTests/
│ │ └── RunnerTests.swift
│ └── packaging/
│ └── dmg/
│ └── make_config.yaml
├── pubspec.yaml
├── test/
│ ├── base64_test.dart
│ ├── cert_test.dart
│ ├── favorites_trim_test.dart
│ ├── http_test.dart
│ ├── js.js
│ ├── js_test.dart
│ ├── pk12_test.dart
│ ├── requests_test.py
│ ├── temp_ipv6_test.dart
│ ├── tests.dart
│ ├── url_test.dart
│ ├── web_test.dart
│ ├── websocket.dart
│ ├── websocket_persistence_test.dart
│ ├── widget_test.dart
│ └── x509_test.dart
└── windows/
├── .gitignore
├── CMakeLists.txt
├── flutter/
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
├── packaging/
│ ├── exe/
│ │ ├── inno_setup.sas
│ │ └── make_config.yaml
│ └── msix/
│ └── make_config.yaml
└── runner/
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: Bug report
description: Create reports to help us improve
labels: bug
body:
- type: dropdown
attributes:
label: Operating system
description: Operating system type
options:
- iOS
- macOS
- Android
- Windows
- Linux
- All
validations:
required: true
- type: textarea
attributes:
label: 描述错误(Describe the bug)
description: Please provide a detailed description of the error.
validations:
required: true
- type: textarea
attributes:
label: To Reproduce
description: "重现行为的步骤: 如具体应用抓包失败,请说明软件名称以及具体操作页面."
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: Feature request
description: Suggest an idea for this project
labels: enhancement
body:
- type: dropdown
attributes:
label: Operating system
description: Operating system type
options:
- iOS
- macOS
- Android
- Windows
- Linux
- All
validations:
required: true
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe.
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
- type: checkboxes
id: supporter
attributes:
label: Supporter
options:
- label: I am a [sponsor](https://buymeacoffee.com/proxypin)
================================================
FILE: .github/ISSUE_TEMPLATE/功能请求.yml
================================================
name: 功能请求
description: 为这个项目提出一个想法
labels: enhancement
body:
- type: dropdown
attributes:
label: Operating system
description: Operating system type
options:
- iOS
- macOS
- Android
- Windows
- Linux
- All
validations:
required: true
- type: textarea
attributes:
label: 您的功能请求是否与某个问题相关?请描述.
description: 对问题所在的清晰简洁的描述.
validations:
required: true
- type: textarea
attributes:
label: 描述您想要的解决方案
description: 对您想要的解决方案的清晰简洁的描述.
- type: checkboxes
id: supporter
attributes:
label: 支持我们
options:
- label: 我已经 [赞助](https://afdian.com/a/proxypin)
================================================
FILE: .gitignore
================================================
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
Podfile.lock
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
l10n_errors.txt
pubspec.lock
/dist/
================================================
FILE: .metadata
================================================
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
version:
revision: 796c8ef79279f9c774545b3771238c3098dbefab
channel: stable
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
- platform: ios
create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# ProxyPin
English | [中文](README_CN.md)
## Open source free traffic capture HTTP(S),Support Windows、Mac、Android、IOS、Linux Full platform system
You can use it to intercept, inspect & rewrite HTTP(S) traffic, Support capturing Flutter app traffic, ProxyPin is based on Flutter develop, and the UI is beautiful
and easy to use.
## Features
* Mobile scan code connection: no need to manually configure WiFi proxy, including configuration synchronization. All terminals can scan codes to connect and forward traffic to each other.
* Domain name filtering: Only intercept the traffic you need, and do not intercept other traffic to avoid interference with other applications.
* Search: Search requests according to keywords, response types and other conditions
* Script: Support writing JavaScript scripts to process requests or responses.
* Request Rewrite: Support redirection, support replacement of request or response message, and can also modify request or response according to the increase.
* Request Mapping: Do not request remote services, use local configuration or scripts for response
* Request Decryption: Configure AES decryption key to automatically decrypt HTTP message body
* Request Blocking: Support blocking requests according to URL, and do not send requests to the server.
* History: Automatically save the captured traffic data for easy backtracking and viewing. Support HAR format export and import.
* Others: Favorites, toolbox, common encoding tools, as well as QR codes, regular expressions, etc.
**Mac will prompt untrusted developers when first opened, you need to go to System Preferences-Security & Privacy-Allow any source.**
## Sponsors
If ProxyPin is helpful to you, you are welcome to support us in the following ways to help the project develop in the long term:
* [Buy Me A Coffee](https://buymeacoffee.com/proxypin)
* [AFDIAN](https://afdian.com/a/proxypin)
* Submit feedback and suggestions to help us improve
* Contribute code or documentation to the project
**Your support will be used for project maintenance, feature development, and user experience optimization. Thank you very much!**
## Downloads
Github Releases: https://github.com/wanghongenpin/proxypin/releases
iOS App Store:https://apps.apple.com/app/proxypin/id6450932949
Android Google Play:https://play.google.com/store/apps/details?id=com.network.proxy
TG: https://t.me/proxypin_en
**We will continue to improve the features and experience, as well as optimize the UI.**
<img alt="image" width="580px" height="420px" src="https://github.com/user-attachments/assets/6c1345ab-c95c-415d-ac59-470c764b59a2">.<img alt="image" height="500px" src="https://github.com/user-attachments/assets/3c5572b0-a9e5-497c-8b42-f935e836c164">
================================================
FILE: README_CN.md
================================================
# ProxyPin
[English](README.md) | 中文
## 开源免费抓包工具,支持Windows、Mac、Android、IOS、Linux 全平台系统
您可以使用它来拦截、检查和重写HTTP(S)流量,支持Flutter应用抓包,ProxyPin基于Flutter开发,UI美观易用。
## 核心特性
* 手机扫码连接: 不用手动配置Wifi代理,包括配置同步。所有终端都可以互相扫码连接转发流量。
* 域名过滤: 只拦截您所需要的流量,不拦截其他流量,避免干扰其他应用。
* 搜索:根据关键词响应类型多种条件搜索请求
* 脚本: 支持编写JavaScript脚本来处理请求或响应。
* 请求重写: 支持重定向,支持替换请求或响应报文,也可以根据增则修改请求或或响应。
* 请求映射: 不请求远程服务,使用本地配置或脚本进行响应
* 请求解密: 配置AES解密密钥,自动解密HTTP消息体
* 请求屏蔽: 支持根据URL屏蔽请求,不让请求发送到服务器。
* 历史记录:自动保存抓包的流量数据,方便回溯查看。支持HAR格式导出与导入。
* 其他:收藏、工具箱、常用编码工具、以及二维码、正则等
**Mac首次打开会提示不受信任开发者,需要到系统偏好设置-安全性与隐私-允许任何来源。**
## 赞助
如果您觉得ProxyPin对您有帮助,欢迎通过以下方式支持我们,帮助项目长期发展:
* [爱发电赞助](https://afdian.com/a/proxypin)
* [Buy Me A Coffee](https://buymeacoffee.com/proxypin)
* 提交反馈和建议,帮助我们改进
* 为项目贡献代码或文档
**您的支持将用于项目的维护、功能开发和用户体验优化,非常感谢!**
## 下载地址
国内下载: https://gitee.com/wanghongenpin/proxypin/releases
iOS App Store: https://apps.apple.com/app/proxypin/id6450932949
Android Google Play:https://play.google.com/store/apps/details?id=com.network.proxy
TG: https://t.me/proxypin_tg
**接下来会持续完善功能和体验,UI优化。**
<img alt="image" width="580px" height="420px" src="https://github.com/user-attachments/assets/80f30d64-f2b5-473c-98f5-bae50b309278">.<img alt="image" height="500px" src="https://github.com/user-attachments/assets/3c5572b0-a9e5-497c-8b42-f935e836c164">
================================================
FILE: analysis_options.yaml
================================================
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
formatter:
page_width: 120
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
avoid_print: false
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
================================================
FILE: android/.gitignore
================================================
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks
/app/.cxx/
================================================
FILE: android/app/build.gradle
================================================
import java.util.Properties
import java.io.FileInputStream
import java.io.File
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
namespace "com.network.proxy"
compileSdk flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
// ndkVersion "26.1.10909125"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
packagingOptions {
dex {
useLegacyPackaging true
}
jniLibs {
useLegacyPackaging true
}
}
defaultConfig {
applicationId "com.network.proxy"
ndk { abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64' }
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
multiDexEnabled true
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.release
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
flutter {
source '../..'
}
// Set a fixed APK name for release builds
// Use the older ApplicationVariants API which is compatible across AGP versions
android.applicationVariants.all { variant ->
if (variant.buildType.name == 'release') {
variant.outputs.all { output ->
def apkName = "proxypin-android.apk"
try {
// Newer output API
output.outputFileName = apkName
} catch (Exception e) {
// Fallback for older API
output.outputFile = new File(output.outputFile.parent, apkName)
}
}
}
}
dependencies {
}
================================================
FILE: android/app/proguard-rules.pro
================================================
#Flutter Wrapper
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
-keep class de.prosiebensat1digital.** { *; }
-dontwarn com.google.android.play.core.**
================================================
FILE: android/app/src/debug/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
================================================
FILE: android/app/src/main/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<!-- Declare media/storage permissions. These are required if your app or
plugins directly read media files. You still need to request these at
runtime on Android (and on Android 13+ use the READ_MEDIA_* permissions).
If you prefer to avoid declaring sensitive permissions, use the system
picker / SAF which doesn't require these permissions. -->
<!-- These permissions are removed to comply with Google Play's "Photos and videos" policy.
Use the system photo picker / SAF to avoid requesting broad media access. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" tools:node="remove" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" tools:node="remove" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" tools:node="remove" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove" />
<application
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:label="ProxyPin">
<activity
android:name="com.network.proxy.MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:exported="true"
android:hardwareAccelerated="true"
android:launchMode="singleTop"
android:supportsPictureInPicture="true"
android:theme="@style/LaunchTheme"
android:windowSoftInputMode="adjustResize"
tools:targetApi="n">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".ProxyVpnService"
android:exported="true"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
</service>
<activity
android:name=".VpnAlertDialog"
android:exported="false">
<intent-filter>
<action android:name="com.network.proxy.ProxyVpnService" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/MainActivity.kt
================================================
package com.network.proxy
import android.content.Intent
import android.content.res.Configuration
import com.network.proxy.plugin.AppLifecyclePlugin
import com.network.proxy.plugin.InstalledAppsPlugin
import com.network.proxy.plugin.PictureInPicturePlugin
import com.network.proxy.plugin.ProcessInfoPlugin
import com.network.proxy.plugin.VpnServicePlugin
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
class MainActivity : FlutterActivity() {
private val lifecycleChannel: AppLifecyclePlugin = AppLifecyclePlugin()
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
pluginRegister(flutterEngine)
}
override fun onUserLeaveHint() {
super.onUserLeaveHint()
lifecycleChannel.onUserLeaveHint()
}
override fun onPictureInPictureModeChanged(
isInPictureInPictureMode: Boolean,
newConfig: Configuration?
) {
lifecycleChannel.onPictureInPictureModeChanged(isInPictureInPictureMode)
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
}
/**
* 注册插件
*/
private fun pluginRegister(flutterEngine: FlutterEngine) {
flutterEngine.plugins.add(VpnServicePlugin())
flutterEngine.plugins.add(PictureInPicturePlugin())
flutterEngine.plugins.add(lifecycleChannel)
flutterEngine.plugins.add(InstalledAppsPlugin())
flutterEngine.plugins.add(ProcessInfoPlugin())
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == VpnServicePlugin.REQUEST_CODE) {
if (resultCode == RESULT_OK) {
activity.startService(ProxyVpnService.startVpnIntent(activity))
return
}
val alertDialog = Intent(applicationContext, VpnAlertDialog::class.java)
.setAction("com.network.proxy.ProxyVpnService")
alertDialog.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(alertDialog)
return
}
super.onActivityResult(requestCode, resultCode, data)
}
override fun onDestroy() {
// activity.startService(ProxyVpnService.stopVpnIntent(activity))
super.onDestroy()
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/ProxyVpnService.kt
================================================
package com.network.proxy
import android.app.Activity
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.net.IpPrefix
import android.net.ProxyInfo
import android.net.VpnService
import android.os.Build
import android.os.ParcelFileDescriptor
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import com.network.proxy.plugin.VpnServicePlugin.Companion.REQUEST_CODE
import com.network.proxy.vpn.ProxyVpnThread
import com.network.proxy.vpn.socket.ProtectSocket
import com.network.proxy.vpn.socket.ProtectSocketHolder
import java.net.InetAddress
/**
* VPN服务
* @author wanghongen
*/
class ProxyVpnService : VpnService(), ProtectSocket {
private var vpnInterface: ParcelFileDescriptor? = null
private var vpnThread: ProxyVpnThread? = null
companion object {
const val MAX_PACKET_LEN = 1500
const val VIRTUAL_HOST = "10.0.0.2"
const val PROXY_HOST_KEY = "ProxyHost"
const val PROXY_PORT_KEY = "ProxyPort"
const val ALLOW_APPS_KEY = "AllowApps" //允许的名单
const val DISALLOW_APPS_KEY = "DisallowApps" //禁止的名单
const val SET_SYSTEM_PROXY_KEY = "SetSystemProxy"
const val PROXY_PASS_DOMAINS_KEY = "ProxyPassDomains"
/**
* 动作:断开连接
*/
const val ACTION_DISCONNECT = "DISCONNECT"
/**
* 通知配置
*/
private const val NOTIFICATION_ID = 9527
const val VPN_NOTIFICATION_CHANNEL_ID = "vpn-notifications"
var isRunning = false
var host: String? = null
var port: Int = 9099
var allowApps: ArrayList<String>? = null
var disallowApps: ArrayList<String>? = null
var setSystemProxy: Boolean = true
var proxyPassDomains: ArrayList<String>? = null
fun stopVpnIntent(context: Context): Intent {
return Intent(context, ProxyVpnService::class.java).also {
it.action = ACTION_DISCONNECT
}
}
fun startVpnIntent(
context: Context,
proxyHost: String? = host,
proxyPort: Int? = port,
allowApps: ArrayList<String>? = this.allowApps,
disallowApps: ArrayList<String>? = this.disallowApps,
setSystemProxy: Boolean = true,
proxyPassDomains: ArrayList<String>? = null
): Intent {
return Intent(context, ProxyVpnService::class.java).also {
it.putExtra(PROXY_HOST_KEY, proxyHost)
it.putExtra(PROXY_PORT_KEY, proxyPort)
it.putStringArrayListExtra(ALLOW_APPS_KEY, allowApps)
it.putStringArrayListExtra(DISALLOW_APPS_KEY, disallowApps)
it.putExtra(SET_SYSTEM_PROXY_KEY, setSystemProxy)
it.putStringArrayListExtra(PROXY_PASS_DOMAINS_KEY, proxyPassDomains)
}
}
/**
* 准备vpn<br>
* 设备可能弹出连接vpn提示
*/
fun prepareVpn(
activity: Activity,
host: String,
port: Int,
allowApps: ArrayList<String>?,
disallowApps: ArrayList<String>?,
setSystemProxy: Boolean = true,
proxyPassDomains: ArrayList<String>? = null
): Boolean {
val intent = prepare(activity)
if (intent != null) {
ProxyVpnService.host = host
ProxyVpnService.port = port
ProxyVpnService.allowApps = allowApps
ProxyVpnService.disallowApps = disallowApps
ProxyVpnService.setSystemProxy = setSystemProxy
ProxyVpnService.proxyPassDomains = proxyPassDomains
activity.startActivityForResult(intent, REQUEST_CODE)
return false
}
return true
}
}
override fun onDestroy() {
super.onDestroy()
disconnect()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent == null) {
return START_NOT_STICKY
}
return if (intent.action == ACTION_DISCONNECT) {
disconnect()
START_NOT_STICKY
} else {
val proxyHost = intent.getStringExtra(PROXY_HOST_KEY) ?: (host ?: "127.0.0.1")
val proxyPort = intent.getIntExtra(PROXY_PORT_KEY, port)
val allowPackages =
intent.getStringArrayListExtra(ALLOW_APPS_KEY) ?: allowApps ?: ArrayList()
val disallowPackages =
intent.getStringArrayListExtra(DISALLOW_APPS_KEY) ?: disallowApps ?: ArrayList()
val setSystemProxy = intent.getBooleanExtra(SET_SYSTEM_PROXY_KEY, setSystemProxy)
val proxyPassDomains = intent.getStringArrayListExtra(PROXY_PASS_DOMAINS_KEY)
connect(
proxyHost,
proxyPort,
allowPackages,
disallowPackages,
setSystemProxy,
proxyPassDomains
)
START_STICKY
}
}
private fun disconnect() {
vpnThread?.run { stopThread() }
vpnInterface?.close()
stopForeground(STOP_FOREGROUND_REMOVE)
vpnInterface = null
isRunning = false
}
private fun connect(
proxyHost: String,
proxyPort: Int,
allowPackages: ArrayList<String>?,
disallowPackages: ArrayList<String>?,
setSystemProxy: Boolean = true,
proxyPassDomains: ArrayList<String>? = null
) {
Log.i(
"ProxyVpnService",
"startVpn $proxyHost:$proxyPort systemProxy: $setSystemProxy allowPackages: $allowPackages proxyPassDomains: $proxyPassDomains"
)
host = proxyHost
port = proxyPort
allowApps = allowPackages
disallowApps = disallowPackages
ProxyVpnService.proxyPassDomains = proxyPassDomains
vpnInterface = createVpnInterface(
proxyHost,
proxyPort,
allowPackages,
disallowPackages,
setSystemProxy,
proxyPassDomains
)
if (vpnInterface == null) {
val alertDialog = Intent(applicationContext, VpnAlertDialog::class.java)
.setAction("com.network.proxy.ProxyVpnService")
alertDialog.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(alertDialog)
return
}
ProtectSocketHolder.setProtectSocket(this)
showServiceNotification()
vpnThread = ProxyVpnThread(
vpnInterface!!,
proxyHost,
proxyPort,
proxyPassDomains
)
vpnThread!!.start()
isRunning = true
}
private fun showServiceNotification() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val notificationChannel = NotificationChannel(
VPN_NOTIFICATION_CHANNEL_ID,
"VPN Status",
NotificationManager.IMPORTANCE_LOW
)
notificationManager.createNotificationChannel(notificationChannel)
}
val pendingActivityIntent: PendingIntent =
Intent(this, MainActivity::class.java).let { notificationIntent ->
PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE)
}
val notification: Notification =
NotificationCompat.Builder(this, VPN_NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingActivityIntent)
.setContentTitle(getString(R.string.vpn_active_notification_title))
.setContentText(getString(R.string.vpn_active_notification_content))
.setOngoing(true)
.build()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
startForeground(NOTIFICATION_ID, notification)
}
}
private fun createVpnInterface(
proxyHost: String,
proxyPort: Int,
allowPackages: List<String>?,
disallowApps: ArrayList<String>?,
setSystemProxy: Boolean = true,
proxyPassDomains: ArrayList<String>? = null
):
ParcelFileDescriptor? {
val build = Builder()
.setMtu(MAX_PACKET_LEN)
.addAddress(VIRTUAL_HOST, 32)
.addRoute("0.0.0.0", 0)
.setSession(baseContext.applicationInfo.name)
.setBlocking(true)
// 处理 proxyPassDomains 中的 CIDR 格式,添加到 excludeRoute
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && proxyPassDomains != null) {
applyExcludeRoutes(build, proxyPassDomains)
}
val packages = allowPackages?.filter { it != baseContext.packageName }
if (packages?.isNotEmpty() == true) {
packages.forEach {
build.addAllowedApplication(it)
}
} else {
build.addDisallowedApplication(baseContext.packageName)
}
disallowApps?.forEach {
if (packages?.contains(it) == true) return@forEach
build.addDisallowedApplication(it)
}
build.setConfigureIntent(
PendingIntent.getActivity(
this,
0,
Intent(this, MainActivity::class.java),
PendingIntent.FLAG_IMMUTABLE
)
)
return build.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
setMetered(false)
}
if (setSystemProxy && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Log.d("ProxyVpnService", "set system proxy $proxyHost:$proxyPort")
val buildProxy = ProxyInfo.buildDirectProxy(proxyHost, proxyPort)
setHttpProxy(buildProxy)
}
}.establish()
}
/**
* 应用排除路由规则
* 根据 proxyPassDomains 列表配置 VPN 的 excludeRoute
*
* @param builder VPN Builder 实例
* @param proxyPassDomains 需要排除的域名/IP列表
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun applyExcludeRoutes(builder: Builder, proxyPassDomains: ArrayList<String>) {
proxyPassDomains.forEach { domain ->
try {
val trimmedDomain = domain.trim()
when {
// 2. localhost 或 127.0.0.1
trimmedDomain == "localhost" || trimmedDomain == "127.0.0.1" -> {
Log.d("ProxyVpnService", "Skipped excludeRoute for localhost: $trimmedDomain")
}
// 1. CIDR 格式:192.168.0.0/16
trimmedDomain.contains("/") -> {
addCidrExcludeRoute(builder, trimmedDomain)
}
// 3. 单个 IP 地址(不含通配符)
!trimmedDomain.contains("*") && isValidIpAddress(trimmedDomain) -> {
addSingleIpExcludeRoute(builder, trimmedDomain)
}
// 4. 域名和通配符域名会被跳过(不能用于 excludeRoute)
}
} catch (e: Exception) {
Log.w("ProxyVpnService", "Error processing proxyPassDomain: $domain", e)
}
}
}
/**
* 添加 CIDR 格式的排除路由
* @param builder VPN Builder 实例
* @param cidr CIDR 格式的地址,如 "192.168.0.0/16"
*/
private fun addCidrExcludeRoute(builder: Builder, cidr: String) {
try {
val parts = cidr.split("/")
if (parts.size != 2) {
Log.w("ProxyVpnService", "Invalid CIDR format: $cidr")
return
}
val ipAddress = parts[0]
val prefixLength = parts[1].toIntOrNull()
if (prefixLength == null || prefixLength !in 0..32) {
Log.w("ProxyVpnService", "Invalid prefix length in CIDR: $cidr")
return
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val inetAddress = InetAddress.getByName(ipAddress)
builder.excludeRoute(IpPrefix(inetAddress, prefixLength))
Log.d("ProxyVpnService", "Added excludeRoute: $cidr")
}
} catch (e: Exception) {
Log.w("ProxyVpnService", "Failed to add CIDR excludeRoute: $cidr", e)
}
}
/**
* 添加单个 IP 地址的排除路由
* @param builder VPN Builder 实例
* @param ipAddress IP 地址字符串
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun addSingleIpExcludeRoute(builder: Builder, ipAddress: String) {
val inetAddress = InetAddress.getByName(ipAddress)
builder.excludeRoute(IpPrefix(inetAddress, 32))
Log.d("ProxyVpnService", "Added excludeRoute for single IP: $ipAddress/32")
}
/**
* 检查字符串是否是有效的 IPv4 地址格式
* @param ip IP 地址字符串
* @return 是否是有效的 IPv4 地址
*/
private fun isValidIpAddress(ip: String): Boolean {
return ip.matches(Regex("\\d+\\.\\d+\\.\\d+\\.\\d+"))
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/VpnAlertDialog.kt
================================================
package com.network.proxy
import android.app.Activity
import android.app.AlertDialog
import android.os.Bundle
import kotlin.system.exitProcess
/**
* @author wanghongen
*/
class VpnAlertDialog : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val dialog: AlertDialog = AlertDialog.Builder(this)
.setTitle("提示")
.setMessage("必须添加VPN才能使用")
.setPositiveButton("确认") { _, _ ->
exitProcess(0)
}
.setCancelable(false)
.create()
dialog.show()
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/plugin/AndroidFlutterPlugin.kt
================================================
package com.network.proxy.plugin
import android.app.Activity
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
abstract class AndroidFlutterPlugin : FlutterPlugin, ActivityAware {
protected lateinit var activity: Activity
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity
}
override fun onDetachedFromActivityForConfigChanges() {
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
}
override fun onDetachedFromActivity() {
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/plugin/AppInfo.kt
================================================
package com.network.proxy.plugin
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import java.io.ByteArrayOutputStream
import androidx.core.graphics.createBitmap
class ProcessInfo(name: CharSequence, packageName: String, icon: ByteArray?, versionName: String?) :
HashMap<String, Any?>() {
init {
put("name", name)
put("packageName", packageName)
put("icon", icon)
put("versionName", versionName)
}
fun copy(): ProcessInfo {
val name = this["name"] as? CharSequence ?: ""
val packageName = this["packageName"] as? String ?: ""
val icon = this["icon"] as? ByteArray
val versionName = this["versionName"] as? String
val newInfo = ProcessInfo(name, packageName, icon, versionName)
newInfo.putAll(this)
return newInfo
}
companion object {
fun create(
packageManager: PackageManager,
app: ApplicationInfo,
withIcon: Boolean = true
): ProcessInfo {
val name = packageManager.getApplicationLabel(app)
val packageName = app.packageName
val icon =
if (withIcon) drawableToByteArray(app.loadIcon(packageManager)) else ByteArray(0)
val packageInfo = packageManager.getPackageInfo(app.packageName, 0)
// 部分应用可能没有设置versionName,将导致获取列表操作失败
val versionName = packageInfo.versionName ?: ""
return ProcessInfo(name, packageName, icon, versionName)
}
private fun drawableToByteArray(drawable: Drawable): ByteArray {
val bitmap = drawableToBitmap(drawable)
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
return stream.toByteArray()
}
private fun drawableToBitmap(drawable: Drawable): Bitmap {
if (drawable is BitmapDrawable) {
return drawable.bitmap
}
// 获取宽度和高度,如果无效则使用默认值 96dp
var width = drawable.intrinsicWidth
var height = drawable.intrinsicHeight
// 如果宽度或高度无效(≤ 0),使用默认的 96 作为大小
if (width <= 0) width = 96
if (height <= 0) height = 96
val bitmap = createBitmap(width, height)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/plugin/AppLifecyclePlugin.kt
================================================
package com.network.proxy.plugin
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodChannel
class AppLifecyclePlugin : AndroidFlutterPlugin() {
var channel: MethodChannel? = null
companion object {
const val CHANNEL = "com.proxy/appLifecycle"
}
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(binding.binaryMessenger, CHANNEL)
}
fun onUserLeaveHint() {
channel?.invokeMethod("onUserLeaveHint", null)
}
fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
channel?.invokeMethod("onPictureInPictureModeChanged", isInPictureInPictureMode)
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/plugin/InstalledAppsPlugin.kt
================================================
package com.network.proxy.plugin
import android.content.pm.ApplicationInfo
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodChannel
import java.util.Locale
import java.util.concurrent.Callable
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
/**
* 已经安装应用列表
*
* @author wanghongen
*/
class InstalledAppsPlugin : AndroidFlutterPlugin() {
var channel: MethodChannel? = null
companion object {
const val CHANNEL = "com.proxy/installedApps"
}
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(binding.binaryMessenger, CHANNEL)
channel!!.setMethodCallHandler { call, result ->
when (call.method) {
"getInstalledApps" -> {
val withIcon = call.argument<Boolean>("withIcon") ?: false
val packageNamePrefix = call.argument<String>("packageNamePrefix") ?: ""
val includeSystemApps = call.argument<Boolean>("includeSystemApps") ?: false
Thread {
result.success(
getInstalledApps(
withIcon,
packageNamePrefix,
includeSystemApps
)
)
}.start()
}
"getAppInfo" -> {
val packageName = call.argument<String>("packageName") ?: ""
result.success(getAppInfo(packageName))
}
else -> result.notImplemented()
}
}
}
private fun getAppInfo(packageName: String): ProcessInfo {
val packageManager = activity.packageManager
packageManager.getApplicationInfo(packageName, 0).let { app ->
return ProcessInfo.create(packageManager, app, true)
}
}
private fun isSystemApp(applicationInfo: ApplicationInfo?): Boolean {
if (applicationInfo == null) return false
return (applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) != 0
}
private fun getInstalledApps(
withIcon: Boolean,
packageNamePrefix: String,
includeSystemApps: Boolean
): List<ProcessInfo> {
val packageManager = activity.packageManager
var installedApps = packageManager.getInstalledApplications(0)
if (!includeSystemApps) {
installedApps =
installedApps.filter { app -> !isSystemApp(app) }
}
if (packageNamePrefix.isNotEmpty()) {
installedApps = installedApps.filter { app ->
app.packageName.startsWith(
packageNamePrefix.lowercase(Locale.ENGLISH)
)
}
}
val threadPoolExecutor = Executors.newFixedThreadPool(4)
installedApps.map { app ->
val task: Callable<ProcessInfo> = Callable {
ProcessInfo.create(packageManager, app, withIcon)
}
threadPoolExecutor.submit(task)
}.map { future ->
future.get()
}.let {
threadPoolExecutor.shutdown()
threadPoolExecutor.awaitTermination(3, TimeUnit.SECONDS)
return it
}
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/plugin/PictureInPicturePlugin.kt
================================================
package com.network.proxy.plugin
import android.app.PendingIntent
import android.app.PictureInPictureParams
import android.app.RemoteAction
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.drawable.Icon
import android.os.Build
import android.util.Rational
import com.network.proxy.ProxyVpnService
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodChannel
import android.util.Log
import androidx.core.content.ContextCompat
/**
* 画中画插件
*/
class PictureInPicturePlugin : AndroidFlutterPlugin() {
private var registerBroadcast = false
var channel: MethodChannel? = null
var proxyHost: String? = null
var proxyPort: Int? = null
var allowApps: ArrayList<String>? = null
var disallowApps: ArrayList<String>? = null
///广播事件接受者
private val vpnBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d("com.network.proxy", "onReceive ${intent?.action}")
if (context == null || (intent?.action != VPN_ACTION && intent?.action != CLEAN_ACTION)) {
return
}
if (intent.action == CLEAN_ACTION) {
channel?.invokeMethod("cleanSession", null)
return
}
val isRunning = ProxyVpnService.isRunning
if (isRunning) {
activity.startService(ProxyVpnService.stopVpnIntent(activity))
} else {
val prepareVpn = ProxyVpnService.prepareVpn(activity, proxyHost!!, proxyPort!!, allowApps, disallowApps)
if (prepareVpn) {
activity.startService(
ProxyVpnService.startVpnIntent(
activity,
proxyHost,
proxyPort,
allowApps,
disallowApps
)
)
}
}
//设置画中画参数
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
updatePictureInPictureParams(!isRunning)
}
}
}
companion object {
const val CHANNEL = "com.proxy/pictureInPicture"
const val VPN_ACTION = "VPN_ACTION"
const val CLEAN_ACTION = "CLEAN_ACTION"
}
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(binding.binaryMessenger, CHANNEL)
channel!!.setMethodCallHandler { call, result ->
when (call.method) {
"enterPictureInPictureMode" -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
proxyHost = call.argument<String>("proxyHost")
proxyPort = call.argument<Int>("proxyPort")
allowApps = call.argument<ArrayList<String>>("allowApps")
disallowApps = call.argument<ArrayList<String>>("disallowApps")
val param = updatePictureInPictureParams(ProxyVpnService.isRunning)
if (!registerBroadcast) {
registerBroadcast = true
ContextCompat.registerReceiver(
activity,
vpnBroadcastReceiver,
IntentFilter().apply {
addAction(VPN_ACTION)
addAction(CLEAN_ACTION)
},
ContextCompat.RECEIVER_NOT_EXPORTED
)
}
result.success(activity.enterPictureInPictureMode(param))
}
}
else -> {
result.notImplemented()
}
}
}
}
// 画中画参数
private fun updatePictureInPictureParams(isRunning: Boolean): PictureInPictureParams {
val params = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
PictureInPictureParams.Builder()
.setAspectRatio(Rational(9, 19))
.apply {
setActions(actions(isRunning)) //vpn服务运行中,显示停止按钮
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
setSeamlessResizeEnabled(false)
}
}
.build()
} else {
throw RuntimeException("getPictureInPictureParams error")
}
activity.setPictureInPictureParams(params)
return params
}
//停止vpn服务 RemoteAction
private fun actions(isRunning: Boolean): List<RemoteAction> {
val pIntent: PendingIntent = PendingIntent.getBroadcast(
activity,
if (isRunning) 0 else 1,
Intent(VPN_ACTION).apply { setPackage(activity.packageName) },
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_IMMUTABLE else PendingIntent.FLAG_UPDATE_CURRENT
)
val cleanIntent: PendingIntent = PendingIntent.getBroadcast(
activity,
2,
Intent(CLEAN_ACTION).apply { setPackage(activity.packageName) },
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_IMMUTABLE else PendingIntent.FLAG_UPDATE_CURRENT
)
//vpn服务运行中,显示停止按钮
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return listOf(
RemoteAction(
Icon.createWithResource(
this@PictureInPicturePlugin.activity,
if (isRunning) android.R.drawable.ic_media_pause else android.R.drawable.ic_media_play
), "Proxy", "Proxy", pIntent
),
RemoteAction(
Icon.createWithResource(
this@PictureInPicturePlugin.activity,
android.R.drawable.ic_menu_delete
), "Clean", "Clean", cleanIntent
)
)
} else {
throw RuntimeException("action error")
}
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/plugin/ProcessInfoPlugin.kt
================================================
package com.network.proxy.plugin
import com.network.proxy.vpn.util.ProcessInfoManager
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodChannel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* 进程信息插件
*
* @author wanghongen
*/
class ProcessInfoPlugin : AndroidFlutterPlugin() {
private val processInfoManager = ProcessInfoManager.instance
companion object {
const val CHANNEL = "com.proxy/processInfo"
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
super.onAttachedToActivity(binding)
processInfoManager.activity = binding.activity
}
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
val channel = MethodChannel(binding.binaryMessenger, CHANNEL)
channel.setMethodCallHandler { call, result ->
when (call.method) {
"getProcessByPort" -> {
val host = call.argument<String>("host")
val port = call.argument<Int>("port")
if (port != null) {
CoroutineScope(Dispatchers.IO).launch {
val appInfo = processInfoManager.getProcessInfoByPort(host, port)
withContext(Dispatchers.Main) {
result.success(appInfo)
}
}
} else {
result.error("INVALID_ARGUMENT", "Port is null", null)
}
}
"getRemoteAddressByPort" -> {
val port = call.argument<Int>("port")
result.success(processInfoManager.getRemoteAddressByPort(port!!))
}
else -> {
result.notImplemented()
}
}
}
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/plugin/VpnServicePlugin.kt
================================================
package com.network.proxy.plugin
import com.network.proxy.ProxyVpnService
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodChannel
class VpnServicePlugin : AndroidFlutterPlugin() {
companion object {
const val CHANNEL = "com.proxy/proxyVpn"
const val REQUEST_CODE: Int = 24
}
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
val channel = MethodChannel(binding.binaryMessenger, CHANNEL)
channel.setMethodCallHandler { call, result ->
when (call.method) {
"isRunning" -> {
result.success(ProxyVpnService.isRunning)
}
"startVpn" -> {
val host = call.argument<String>("proxyHost")
val port = call.argument<Int>("proxyPort")
val allowApps = call.argument<ArrayList<String>>("allowApps")
val disallowApps = call.argument<ArrayList<String>>("disallowApps")
val setSystemProxy = call.argument<Boolean>("setSystemProxy") ?: true
val proxyPassDomains = call.argument<ArrayList<String>>("proxyPassDomains")
val prepareVpn = ProxyVpnService.prepareVpn(
activity,
host!!,
port!!,
allowApps,
disallowApps,
setSystemProxy,
proxyPassDomains
)
if (prepareVpn) {
startVpn(host, port, allowApps, disallowApps, setSystemProxy, proxyPassDomains)
}
result.success(prepareVpn)
}
"stopVpn" -> {
stopVpn()
result.success(null)
}
"restartVpn" -> {
val host = call.argument<String>("proxyHost")
val port = call.argument<Int>("proxyPort")
val allowApps = call.argument<ArrayList<String>>("allowApps")
val disallowApps = call.argument<ArrayList<String>>("disallowApps")
val setSystemProxy = call.argument<Boolean>("setSystemProxy") ?: true
val proxyPassDomains = call.argument<ArrayList<String>>("proxyPassDomains")
stopVpn()
startVpn(host!!, port!!, allowApps, disallowApps, setSystemProxy, proxyPassDomains)
result.success(null)
}
else -> {
result.notImplemented()
}
}
}
}
/**
* 启动vpn服务
*/
private fun startVpn(
host: String,
port: Int,
allowApps: ArrayList<String>? = arrayListOf(),
disallowApps: ArrayList<String>? = arrayListOf(),
setSystemProxy: Boolean = true,
proxyPassDomains: ArrayList<String>? = null
) {
val intent = ProxyVpnService.startVpnIntent(
activity,
host,
port,
allowApps,
disallowApps,
setSystemProxy,
proxyPassDomains
)
activity.startService(intent)
}
/**
* 停止vpn服务
*/
private fun stopVpn() {
activity.startService(ProxyVpnService.stopVpnIntent(activity))
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/Connection.kt
================================================
package com.network.proxy.vpn
import android.util.Log
import com.network.proxy.vpn.socket.CloseableConnection
import com.network.proxy.vpn.transport.protocol.IP4Header
import com.network.proxy.vpn.transport.protocol.TCPHeader
import com.network.proxy.vpn.transport.protocol.UDPHeader
import com.network.proxy.vpn.util.PacketUtil
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.nio.ByteBuffer
import java.nio.channels.SelectionKey
import java.nio.channels.spi.AbstractSelectableChannel
import kotlin.concurrent.Volatile
class Connection(
val protocol: Protocol,
val sourceIp: Int, val sourcePort: Int,
val destinationIp: Int, val destinationPort: Int,
private val connectionCloser: CloseableConnection
) {
var channel: AbstractSelectableChannel? = null
var selectionKey: SelectionKey? = null
//接收用于存储来自远程主机的数据的缓冲器
private val receivingStream: ByteArrayOutputStream = ByteArrayOutputStream()
//发送缓冲区,用于存储要从vpn客户端发送到目标主机的数据
private val sendingStream: ByteArrayOutputStream = ByteArrayOutputStream()
var hasReceivedLastSegment = false
/**
* 是否初始化链接 针对代理判断协议延迟初始化
*/
var isInitConnect = false
//指示三向握手是否已完成
var isConnected = false
//从客户端接收的最后一个数据包
var lastIpHeader: IP4Header? = null
var lastTcpHeader: TCPHeader? = null
var lastUdpHeader: UDPHeader? = null
var timestampSender = 0
var timestampReplyTo = 0
//从客户端接收的序列
var recSequence: Long = 0
//在tcp选项内的SYN期间由客户端发送
var maxSegmentSize = 0
//跟踪我们发送给客户端的ack,并等待客户端返回ack
var sendUnAck: Long = 0
//发送到客户端的下一个ack
var sendNext: Long = 0
//true when connection is about to be close
var isClosingConnection = false
//指示客户端的数据已准备好发送到目标
@Volatile
var isDataForSendingReady = false
//closing session and aborting connection, will be done by background task
@Volatile
var isAbortingConnection = false
//indicate that vpn client has sent FIN flag and it has been acked
var isAckedToFin = false
companion object {
fun getConnectionKey(
protocol: Protocol, destIp: Int, destPort: Int, sourceIp: Int, sourcePort: Int
): String {
return protocol.name + "|" + PacketUtil.intToIPAddress(sourceIp) + ":" + sourcePort +
"->" + PacketUtil.intToIPAddress(destIp) + ":" + destPort
}
}
// fun getConnectionKey(): String {
// return getConnectionKey(protocol, destinationIp, destinationIp, sourceIp, sourcePort)
// }
fun closeConnection() {
connectionCloser.closeConnection(this)
}
/**
* 设置要发送到目标服务器的数据
*/
@Synchronized
fun setSendingData(data: ByteBuffer): Int {
val remaining = data.remaining()
sendingStream.write(data.array(), data.position(), data.remaining())
return remaining
}
@Synchronized
fun addReceivedData(data: ByteArray?) {
try {
receivingStream.write(data)
} catch (e: IOException) {
Log.e(TAG, e.toString())
}
}
/**
* 获取缓冲区中接收到的所有数据并清空它。
*/
@Synchronized
fun getReceivedData(maxSize: Int): ByteArray? {
var data = receivingStream.toByteArray()
receivingStream.reset()
if (data.size > maxSize) {
val small = ByteArray(maxSize)
System.arraycopy(data, 0, small, 0, maxSize)
val len = data.size - maxSize
receivingStream.write(data, maxSize, len)
data = small
}
return data
}
/**
* buffer has more data for vpn client
*/
fun hasReceivedData(): Boolean {
return receivingStream.size() > 0
}
fun hasDataToSend(): Boolean {
return sendingStream.size() > 0
}
/**
* 出列数据以发送到服务器
*/
@Synchronized
fun getSendingData(): ByteArray? {
val data = sendingStream.toByteArray()
sendingStream.reset()
return data
}
fun cancelKey() {
selectionKey?.let {
synchronized(it) {
if (!it.isValid) return
it.cancel()
}
}
}
fun subscribeKey(op: Int) {
selectionKey?.let {
synchronized(it) {
if (!it.isValid) return
it.interestOps(it.interestOps() or op)
}
}
}
fun unsubscribeKey(op: Int) {
selectionKey?.let {
synchronized(it) {
if (!it.isValid) return
it.interestOps(it.interestOps() and op.inv())
}
}
}
override fun toString(): String {
return "Connection{" +
"protocol=" + protocol +
", sourceIp=" + PacketUtil.intToIPAddress(sourceIp) +
", sourcePort=" + sourcePort +
", destinationIp=" + PacketUtil.intToIPAddress(destinationIp) +
", destinationPort=" + destinationPort +
'}'
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/ConnectionHandler.kt
================================================
package com.network.proxy.vpn
import android.util.Log
import com.network.proxy.vpn.Connection.Companion.getConnectionKey
import com.network.proxy.vpn.socket.ClientPacketWriter
import com.network.proxy.vpn.socket.SocketNIODataService
import com.network.proxy.vpn.transport.icmp.ICMPPacket
import com.network.proxy.vpn.transport.icmp.ICMPPacketFactory
import com.network.proxy.vpn.transport.protocol.IP4Header
import com.network.proxy.vpn.transport.protocol.IPPacketFactory
import com.network.proxy.vpn.transport.protocol.TCPHeader
import com.network.proxy.vpn.transport.protocol.TCPPacketFactory
import com.network.proxy.vpn.transport.protocol.UDPPacketFactory
import com.network.proxy.vpn.util.PacketUtil.getOutput
import com.network.proxy.vpn.util.PacketUtil.intToIPAddress
import com.network.proxy.vpn.util.PacketUtil.isPacketCorrupted
import com.network.proxy.vpn.util.ProcessInfoManager
import com.network.proxy.vpn.util.TLS.isTLSClientHello
import java.io.IOException
import java.net.InetAddress
import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.channels.SelectionKey
import java.nio.channels.SocketChannel
import java.util.concurrent.ExecutorService
import java.util.concurrent.SynchronousQueue
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit
class ConnectionHandler(
private val manager: ConnectionManager,
private val nioService: SocketNIODataService,
private val writer: ClientPacketWriter
) {
private val pingThreadPool: ExecutorService = ThreadPoolExecutor(
1, 20, // 1 - 20 parallel pings max
60L, TimeUnit.SECONDS,
SynchronousQueue(),
ThreadPoolExecutor.DiscardPolicy() // Replace running pings if there's too many
)
/**
* Handle unknown raw IP packet data
*
* @param stream ByteBuffer to be read
*/
@Throws(IOException::class)
fun handlePacket(stream: ByteBuffer) {
stream.rewind()
val ipHeader = IPPacketFactory.createIP4Header(stream)
if (ipHeader == null) {
stream.rewind()
Log.w(TAG, "Malformed IP packet ")
return
}
if (ipHeader.protocol.toInt() == 6) {
handleTCPPacket(stream, ipHeader)
} else if (ipHeader.protocol.toInt() == 17) {
handleUDPPacket(stream, ipHeader)
} else if (ipHeader.protocol.toInt() == 1) {
handleICMPPacket(stream, ipHeader)
} else {
Log.w(TAG, "Unsupported IP protocol: " + ipHeader.protocol)
}
}
@Throws(IOException::class)
private fun handleUDPPacket(clientPacketData: ByteBuffer, ipHeader: IP4Header) {
val udpHeader = UDPPacketFactory.createUDPHeader(clientPacketData)
var connection = manager.getConnection(
Protocol.UDP,
ipHeader.destinationIP, udpHeader.destinationPort,
ipHeader.sourceIP, udpHeader.sourcePort
)
val newSession = connection == null
if (connection == null) {
connection = manager.createUDPConnection(
ipHeader.destinationIP, udpHeader.destinationPort,
ipHeader.sourceIP, udpHeader.sourcePort
)
}
synchronized(connection) {
connection.lastIpHeader = ipHeader
connection.lastUdpHeader = udpHeader
manager.addClientData(clientPacketData, connection)
connection.isDataForSendingReady = true
// We don't register the session until it's fully populated (as above)
if (newSession) nioService.registerSession(connection)
// Ping the NIO thread to write this, when the session is next writable
connection.subscribeKey(SelectionKey.OP_WRITE)
nioService.refreshSelect(connection)
}
manager.keepSessionAlive(connection)
}
/**
* 是否支持协议
*/
private val methods: List<String> =
mutableListOf("GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS", "TRACE", "CONNECT", "PROPFIND", "REPORT")
private fun supperProtocol(packetData: ByteBuffer): Boolean {
val position = packetData.position()
//判断是否是ssl握手
if (isTLSClientHello(packetData)) {
packetData.position(position)
return true
}
packetData.position(position)
for (method in methods) {
if (packetData.remaining() < method.length) {
continue
}
val bytes = ByteArray(method.length)
for (i in bytes.indices) {
bytes[i] = packetData[position + i]
}
if (method.equals(String(bytes), ignoreCase = true)) {
return true
}
}
return false
}
/**
* 获取代理地址
*/
private fun getProxyAddress(
packetData: ByteBuffer, destinationIP: Int, destinationPort: Int
): InetSocketAddress {
val ips = intToIPAddress(destinationIP)
// 检查是否在代理过滤列表中
if (shouldBypassProxy(ips)) {
Log.d(TAG, "Bypassing proxy for $ips (in proxyPassDomains)")
return InetSocketAddress(ips, destinationPort)
}
val supperProtocol = supperProtocol(packetData)
var socketAddress: InetSocketAddress? = null
if (supperProtocol) {
socketAddress = manager.proxyAddress
}
if (socketAddress == null) {
socketAddress = InetSocketAddress(ips, destinationPort)
}
return socketAddress
}
/**
* 检查是否应该绕过代理
* 支持 CIDR 格式(如 192.168.0.0/16)、IP地址、localhost 和域名(带通配符)匹配
*/
private fun shouldBypassProxy(destinationIP: String): Boolean {
val proxyPassDomains = manager.proxyPassDomains ?: return false
for (domain in proxyPassDomains) {
try {
val trimmedDomain = domain.trim()
// 处理 localhost
if (trimmedDomain == "localhost" && (destinationIP == "127.0.0.1" || destinationIP == "localhost")) {
return true
}
// 处理 CIDR 格式,如 192.168.0.0/16
if (trimmedDomain.contains("/")) {
if (matchesCIDR(destinationIP, trimmedDomain)) {
return true
}
} else if (trimmedDomain.startsWith("*.")) {
// 支持通配符匹配,如 *.example.com
val suffix = trimmedDomain.substring(1) // 去掉 *
if (destinationIP.endsWith(suffix)) {
return true
}
} else if (trimmedDomain.contains("*")) {
// 支持其他通配符模式
val pattern = trimmedDomain.replace(".", "\\.").replace("*", ".*")
if (destinationIP.matches(Regex(pattern))) {
return true
}
} else {
// 精确匹配 IP 或域名
if (destinationIP == trimmedDomain) {
return true
}
// 尝试解析域名为IP地址进行比较
try {
val address = InetAddress.getByName(trimmedDomain)
if (address.hostAddress == destinationIP) {
return true
}
} catch (e: Exception) {
Log.w(TAG, "Error resolving domain $trimmedDomain: ${e.message}")
}
}
} catch (e: Exception) {
Log.w(TAG, "Error matching domain $domain: ${e.message}")
}
}
return false
}
/**
* 检查 IP 地址是否匹配 CIDR 格式
* @param ip 目标 IP 地址,如 "192.168.1.1"
* @param cidr CIDR 格式,如 "192.168.0.0/16"
* @return 是否匹配
*/
private fun matchesCIDR(ip: String, cidr: String): Boolean {
try {
val parts = cidr.split("/")
if (parts.size != 2) return false
val networkAddress = parts[0]
val prefixLength = parts[1].toIntOrNull() ?: return false
val ipBytes = ipToBytes(ip)
val networkBytes = ipToBytes(networkAddress)
if (ipBytes == null || networkBytes == null) return false
// 计算掩码
val mask = (-1L shl (32 - prefixLength)).toInt()
// 将 IP 地址转换为整数进行比较
val ipInt = bytesToInt(ipBytes)
val networkInt = bytesToInt(networkBytes)
return (ipInt and mask) == (networkInt and mask)
} catch (e: Exception) {
Log.w(TAG, "Error matching CIDR $cidr for IP $ip: ${e.message}")
return false
}
}
/**
* 将 IP 地址字符串转换为字节数组
*/
private fun ipToBytes(ip: String): ByteArray? {
try {
val parts = ip.split(".")
if (parts.size != 4) return null
return ByteArray(4) { i ->
parts[i].toInt().toByte()
}
} catch (_: Exception) {
return null
}
}
/**
* 将字节数组转换为整数
*/
private fun bytesToInt(bytes: ByteArray): Int {
return ((bytes[0].toInt() and 0xFF) shl 24) or
((bytes[1].toInt() and 0xFF) shl 16) or
((bytes[2].toInt() and 0xFF) shl 8) or
(bytes[3].toInt() and 0xFF)
}
@Throws(IOException::class)
private fun handleTCPPacket(clientPacketData: ByteBuffer, ip4Header: IP4Header) {
val tcpHeader = TCPPacketFactory.createTCPHeader(clientPacketData)
val dataLength = clientPacketData.limit() - clientPacketData.position()
val sourceIP = ip4Header.sourceIP
val destinationIP = ip4Header.destinationIP
val sourcePort = tcpHeader.getSourcePort()
val destinationPort = tcpHeader.getDestinationPort()
if (tcpHeader.isSYN()) {
// 3-way handshake + create new session
replySynAck(ip4Header, tcpHeader)
} else if (tcpHeader.isACK()) {
val key =
getConnectionKey(Protocol.TCP, destinationIP, destinationPort, sourceIP, sourcePort)
val connection = manager.getConnectionByKey(key)
if (connection == null) {
Log.w(TAG, "Ack for unknown session: $key")
if (tcpHeader.isFIN()) {
sendLastAck(ip4Header, tcpHeader)
} else if (!tcpHeader.isRST()) {
sendRstPacket(ip4Header, tcpHeader, dataLength)
}
return
}
synchronized(connection) {
connection.lastIpHeader = ip4Header
connection.lastTcpHeader = tcpHeader
//any data from client?
if (dataLength > 0) {
//init proxy
initProxyConnect(clientPacketData, destinationIP, destinationPort, connection)
//accumulate data from client
if (connection.recSequence == 0L || tcpHeader.sequenceNumber >= connection.recSequence) {
val addedLength = manager.addClientData(clientPacketData, connection)
//send ack to client only if new data was added
sendAck(ip4Header, tcpHeader, addedLength, connection)
} else {
sendAckForDisorder(ip4Header, tcpHeader, dataLength)
}
} else {
//an ack from client for previously sent data
acceptAck(tcpHeader, connection)
if (connection.isClosingConnection) {
sendFinAck(ip4Header, tcpHeader, connection)
} else if (connection.isAckedToFin && !tcpHeader.isFIN()) {
//the last ACK from client after FIN-ACK flag was sent
manager.closeConnection(
Protocol.TCP,
destinationIP,
destinationPort,
sourceIP,
sourcePort
)
// Log.d(TAG, "got last ACK after FIN, session is now closed.");
}
}
//received the last segment of data from vpn client
if (tcpHeader.isPSH()) {
// Tell the NIO thread to immediately send data to the destination
pushDataToDestination(connection, tcpHeader)
} else if (tcpHeader.isFIN()) {
//fin from vpn client is the last packet
//ack it
// Log.d(TAG, "FIN from vpn client, will ack it.");
ackFinAck(ip4Header, tcpHeader, connection)
} else if (tcpHeader.isRST()) {
resetTCPConnection(ip4Header, tcpHeader)
}
if (!connection.isAbortingConnection) {
manager.keepSessionAlive(connection)
}
}
} else if (tcpHeader.isFIN()) {
//case client sent FIN without ACK
val connection = manager.getConnection(
Protocol.TCP,
destinationIP,
destinationPort,
sourceIP,
sourcePort
)
if (connection == null) ackFinAck(
ip4Header,
tcpHeader,
null
) else manager.keepSessionAlive(connection)
} else if (tcpHeader.isRST()) {
resetTCPConnection(ip4Header, tcpHeader)
} else {
Log.d(TAG, "unknown TCP flag")
val str1 = getOutput(ip4Header, tcpHeader, clientPacketData.array())
Log.d(TAG, ">>>>>>>> Received from client <<<<<<<<<<")
Log.d(TAG, str1)
Log.d(TAG, ">>>>>>>>>>>>>>>>>>>end receiving from client>>>>>>>>>>>>>>>>>>>>>")
}
}
private fun initProxyConnect(
clientPacketData: ByteBuffer, destinationIP: Int, destinationPort: Int,
connection: Connection
) {
if (connection.isInitConnect) {
return
}
connection.isInitConnect = true
val proxyAddress =
getProxyAddress(clientPacketData, destinationIP, destinationPort)
try {
val channel = connection.channel as SocketChannel?
val connected = channel!!.connect(proxyAddress)
connection.isConnected = connected
nioService.registerSession(connection)
if (proxyAddress == manager.proxyAddress) {
//获取进程信息
ProcessInfoManager.instance.setConnectionOwnerUid(connection)
Log.d(
TAG,
"Proxy Initiate connecting key:" + connection.toString() + " " + channel.localAddress + " to remote tcp server: " + channel.remoteAddress
)
}
} catch (e: Exception) {
val ips = intToIPAddress(destinationIP)
Log.w(TAG, "Failed to reconnect to $ips:$destinationPort", e)
}
}
private fun sendRstPacket(ip: IP4Header, tcp: TCPHeader, dataLength: Int) {
val data = TCPPacketFactory.createRstData(ip, tcp, dataLength)
writer.write(data)
Log.d(
TAG, "Sent RST Packet to client with dest => " +
intToIPAddress(ip.destinationIP) + ":" +
tcp.getDestinationPort()
)
}
private fun sendLastAck(ip: IP4Header, tcp: TCPHeader) {
val data = TCPPacketFactory.createResponseAckData(ip, tcp, tcp.sequenceNumber + 1)
writer.write(data)
// Log.d(TAG,"Sent last ACK Packet to client with dest => " +
// PacketUtil.intToIPAddress(ip.getDestinationIP()) + ":" +
// tcp.getDestinationPort());
}
private fun ackFinAck(ip: IP4Header, tcp: TCPHeader, connection: Connection?) {
val ack = tcp.sequenceNumber + 1
val seq = tcp.ackNumber
val data = TCPPacketFactory.createFinAckData(ip, tcp, ack, seq, isFin = true, isAck = true)
writer.write(data)
if (connection != null) {
connection.cancelKey()
manager.closeConnection(connection)
// Log.d(TAG,"ACK to client's FIN and close session => "+PacketUtil.intToIPAddress(ip.getDestinationIP())+":"+tcp.getDestinationPort()
// +"-"+PacketUtil.intToIPAddress(ip.getSourceIP())+":"+tcp.getSourcePort());
}
}
private fun sendFinAck(ip: IP4Header, tcp: TCPHeader, connection: Connection) {
val ack = tcp.sequenceNumber
val seq = tcp.ackNumber
val data = TCPPacketFactory.createFinAckData(ip, tcp, ack, seq, isFin = true, isAck = false)
val stream = ByteBuffer.wrap(data)
writer.write(data)
// Log.d(TAG, "00000000000 FIN-ACK packet data to vpn client 000000000000")
var vpnIp: IP4Header? = null
try {
vpnIp = IPPacketFactory.createIP4Header(stream)
} catch (e: Exception) {
e.printStackTrace()
}
var vpnTcp: TCPHeader? = null
try {
if (vpnIp != null) vpnTcp = TCPPacketFactory.createTCPHeader(stream)
} catch (e: Exception) {
e.printStackTrace()
}
if (vpnIp != null && vpnTcp != null) {
val logOut = getOutput(vpnIp, vpnTcp, data)
Log.d(TAG, logOut)
}
// Log.d(TAG, "0000000000000 finished sending FIN-ACK packet to vpn client 000000000000")
connection.sendNext = seq + 1
//avoid re-sending it, from here client should take care the rest
connection.isClosingConnection = false
}
private fun pushDataToDestination(connection: Connection, tcp: TCPHeader) {
connection.isDataForSendingReady = true
connection.timestampReplyTo = tcp.timeStampSender
connection.timestampSender = System.currentTimeMillis().toInt()
// Ping the NIO thread to write this, when the session is next writable
connection.subscribeKey(SelectionKey.OP_WRITE)
nioService.refreshSelect(connection)
}
/**
* send acknowledgment packet to VPN client
*
* @param acceptedDataLength Data Length
*/
private fun sendAck(
ipHeader: IP4Header, tcpHeader: TCPHeader, acceptedDataLength: Int, connection: Connection
) {
val ackNumber = connection.recSequence + acceptedDataLength
connection.recSequence = ackNumber
val ackData = TCPPacketFactory.createResponseAckData(ipHeader, tcpHeader, ackNumber)
writer.write(ackData)
}
/**
* resend the last acknowledgment packet to VPN client, e.g. when an unexpected out of order
* packet arrives.
*/
private fun resendAck(connection: Connection) {
val data = TCPPacketFactory.createResponseAckData(
connection.lastIpHeader!!,
connection.lastTcpHeader!!,
connection.recSequence
)
writer.write(data)
}
private fun sendAckForDisorder(
ipHeader: IP4Header, tcpHeader: TCPHeader, acceptedDataLength: Int
) {
val ackNumber = tcpHeader.sequenceNumber + acceptedDataLength
Log.e(
TAG, "sent disorder ack, ack# " + tcpHeader.sequenceNumber +
" + " + acceptedDataLength + " = " + ackNumber
)
val data = TCPPacketFactory.createResponseAckData(ipHeader, tcpHeader, ackNumber)
writer.write(data)
}
/**
* acknowledge a packet.
*
* @param tcpHeader TCP Header
*/
private fun acceptAck(tcpHeader: TCPHeader, connection: Connection) {
val isCorrupted = isPacketCorrupted(tcpHeader)
// connection.setPacketCorrupted(isCorrupted);
if (isCorrupted) {
Log.e(TAG, "prev packet was corrupted, last ack# " + tcpHeader.ackNumber)
}
if (tcpHeader.ackNumber > connection.sendUnAck ||
tcpHeader.ackNumber == connection.sendNext
) {
// connection.setAcked(true);
connection.sendUnAck = tcpHeader.ackNumber
connection.recSequence = tcpHeader.sequenceNumber
connection.timestampReplyTo = tcpHeader.timeStampSender
connection.timestampSender = System.currentTimeMillis().toInt()
} else {
Log.d(
TAG,
"Not Accepting ack# " + tcpHeader.ackNumber + " , it should be: " + connection.sendNext
)
Log.d(TAG, "Prev sendUnAck: " + connection.sendUnAck)
// connection.setAcked(false);
}
}
/**
* set connection as aborting so that background worker will close it.
*
* @param ip IP
* @param tcp TCP
*/
private fun resetTCPConnection(ip: IP4Header, tcp: TCPHeader) {
val session = manager.getConnection(
Protocol.TCP,
ip.destinationIP, tcp.getDestinationPort(),
ip.sourceIP, tcp.getSourcePort()
)
if (session != null) {
synchronized(session) { session.isAbortingConnection = true }
}
}
/**
* create a new client's session and SYN-ACK packet data to respond to client
*/
@Throws(IOException::class)
private fun replySynAck(ipHeader: IP4Header, tcpHeader: TCPHeader) {
ipHeader.identification = 0
val packet = TCPPacketFactory.createSynAckPacketData(ipHeader, tcpHeader)
val tcpTransport = packet.transportHeader as TCPHeader
val connection = manager.createTCPConnection(
ipHeader.destinationIP, tcpHeader.getDestinationPort(),
ipHeader.sourceIP, tcpHeader.getSourcePort()
)
if (connection.lastIpHeader != null) {
// We have an existing session for this connection! We've somehow received a SYN
// for an existing socket (or some kind of other race). We resend the last ACK
// for this session, rejecting this SYN. Not clear why this happens, but it can.
resendAck(connection)
return
}
synchronized(connection) {
connection.maxSegmentSize = tcpTransport.maxSegmentSize.toInt()
connection.sendUnAck = tcpTransport.sequenceNumber
connection.sendNext = tcpTransport.sequenceNumber + 1
//client initial sequence has been incremented by 1 and set to ack
connection.recSequence = tcpTransport.ackNumber
connection.lastIpHeader = ipHeader
connection.lastTcpHeader = tcpHeader
if (connection.isInitConnect) {
nioService.registerSession(connection)
}
writer.write(packet.buffer)
}
}
private fun handleICMPPacket(clientPacketData: ByteBuffer, ipHeader: IP4Header) {
val requestPacket = ICMPPacketFactory.parseICMPPacket(clientPacketData)
// Log.d(TAG, "Got an ICMP ping packet, type $requestPacket")
if (requestPacket.type == ICMPPacket.DESTINATION_UNREACHABLE_TYPE) {
// This is a packet from the phone, telling somebody that a destination is unreachable.
// Might be caused by issues on our end, but it's unclear what kind of issues. Regardless,
// we can't send ICMP messages ourselves or react usefully, so we drop these silently.
return
} else require(requestPacket.type == ICMPPacket.ECHO_REQUEST_TYPE) {
// We only actually support outgoing ping packets. Loudly drop anything else:
"Unknown ICMP type (" + requestPacket.type + "). Only echo requests are supported"
}
pingThreadPool.execute(object : Runnable {
override fun run() {
try {
if (!isReachable(intToIPAddress(ipHeader.destinationIP))) {
Log.d(TAG, "Failed ping, ignoring")
return
}
val response = ICMPPacketFactory.buildSuccessPacket(requestPacket)
// Flip the address
val destination = ipHeader.destinationIP
val source = ipHeader.sourceIP
ipHeader.sourceIP = destination
ipHeader.destinationIP = source
val responseData = ICMPPacketFactory.packetToBuffer(ipHeader, response)
Log.d(TAG, "Successful ping response")
writer.write(responseData)
} catch (e: Exception) {
Log.w(TAG, "Handling ICMP failed with " + e.message)
return
}
}
private fun isReachable(ipAddress: String): Boolean {
return try {
InetAddress.getByName(ipAddress).isReachable(10000)
} catch (_: IOException) {
false
}
}
})
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/ConnectionManager.kt
================================================
package com.network.proxy.vpn
import android.os.Build
import android.util.Log
import com.network.proxy.vpn.socket.CloseableConnection
import com.network.proxy.vpn.socket.Constant
import com.network.proxy.vpn.socket.ProtectSocketHolder.Companion.protect
import com.network.proxy.vpn.util.PacketUtil
import com.network.proxy.vpn.util.ProcessInfoManager
import java.io.IOException
import java.net.InetSocketAddress
import java.net.SocketAddress
import java.nio.ByteBuffer
import java.nio.channels.DatagramChannel
import java.nio.channels.SocketChannel
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
/**
* 管理VPN客户端的连接
*/
class ConnectionManager private constructor() : CloseableConnection {
//单例
companion object {
private const val TAG = "ConnectionManager"
val instance = ConnectionManager()
}
private val table: ConcurrentMap<String, Connection> = ConcurrentHashMap()
var proxyAddress: InetSocketAddress? = null
var proxyPassDomains: ArrayList<String>? = null
private val DEFAULT_PORTS: List<Int> = listOf(
80, // HTTP
443, // HTTPS
8080, // Common local dev ports
8000, 8080, 8888, 9000 // Common local dev ports
)
override fun closeConnection(connection: Connection) {
closeConnection(
connection.protocol, connection.destinationIp, connection.destinationPort,
connection.sourceIp, connection.sourcePort
)
}
/**
* 从内存中删除连接,然后关闭套接字。
*
*/
fun closeConnection(protocol: Protocol, ip: Int, port: Int, srcIp: Int, srcPort: Int) {
val key = Connection.getConnectionKey(protocol, ip, port, srcIp, srcPort)
val connection: Connection? = table.remove(key)
Log.d(TAG, "close connection $key")
connection?.let {
val channel = connection.channel
try {
channel?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
fun getConnection(
protocol: Protocol, ip: Int, port: Int, srcIp: Int, srcPort: Int
): Connection? {
val key = Connection.getConnectionKey(protocol, ip, port, srcIp, srcPort)
return getConnectionByKey(key)
}
fun getConnectionByKey(key: String?): Connection? {
return table[key]
}
/**
* 创建tcp连接
*/
fun createTCPConnection(ip: Int, port: Int, srcIp: Int, srcPort: Int): Connection {
val key = Connection.getConnectionKey(Protocol.TCP, ip, port, srcIp, srcPort)
val existingConnection: Connection? = table[key]
if (existingConnection != null) {
return existingConnection
}
val connection = Connection(Protocol.TCP, srcIp, srcPort, ip, port, this)
val channel: SocketChannel = SocketChannel.open()
channel.socket().keepAlive = true
channel.socket().tcpNoDelay = true
channel.socket().soTimeout = 0
channel.socket().receiveBufferSize = Constant.MAX_RECEIVE_BUFFER_SIZE
channel.configureBlocking(false)
Log.d(TAG, "created new SocketChannel for $key")
protect(channel.socket())
connection.channel = channel
var socketAddress: SocketAddress? = null
// if (DEFAULT_PORTS.contains(port)) {
// socketAddress = proxyAddress
// }
connection.isInitConnect = socketAddress != null
if (socketAddress != null) {
val connected = channel.connect(socketAddress)
connection.isConnected = connected
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//获取进程信息
ProcessInfoManager.instance.setConnectionOwnerUid(connection)
Log.d(
TAG,
"Initiate connecting " + channel.localAddress + " to remote tcp server: " + channel.remoteAddress
)
}
}
table[key] = connection
return connection
}
@Throws(IOException::class)
fun createUDPConnection(ip: Int, port: Int, srcIp: Int, srcPort: Int): Connection {
val keys = Connection.getConnectionKey(Protocol.UDP, ip, port, srcIp, srcPort)
val existingConnection: Connection? = table[keys]
if (existingConnection != null) return existingConnection
val connection = Connection(Protocol.UDP, srcIp, srcPort, ip, port, this)
val channel: DatagramChannel = DatagramChannel.open()
channel.socket().soTimeout = 0
channel.configureBlocking(false)
protect(channel.socket())
connection.channel = channel
// Initiate connection early to reduce latency
val ips = PacketUtil.intToIPAddress(ip)
val socketAddress: SocketAddress = InetSocketAddress(ips, port)
channel.connect(socketAddress)
connection.isConnected = channel.isConnected
table[keys] = connection
return connection
}
/**
* 添加来自客户端的数据,该数据稍后将在接收到PSH标志时发送到目的服务器。
*/
fun addClientData(buffer: ByteBuffer, session: Connection): Int {
return if (buffer.limit() <= buffer.position()) 0 else session.setSendingData(buffer)
}
/**
* 阻止java垃圾收集器收集会话
*/
fun keepSessionAlive(connection: Connection) {
val key = Connection.getConnectionKey(
connection.protocol, connection.destinationIp, connection.destinationPort,
connection.sourceIp, connection.sourcePort
)
table[key] = connection
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/Protocol.java
================================================
package com.network.proxy.vpn;
public enum Protocol {
TCP,
UDP
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/ProxyVpnThread.kt
================================================
package com.network.proxy.vpn
import android.os.ParcelFileDescriptor
import android.util.Log
import com.network.proxy.ProxyVpnService.Companion.MAX_PACKET_LEN
import com.network.proxy.vpn.socket.ClientPacketWriter
import com.network.proxy.vpn.socket.SocketNIODataService
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.InterruptedIOException
import java.net.InetSocketAddress
import java.nio.ByteBuffer
/**
* VPN线程,负责处理VPN接收到的数据包
* @author wanghongen
*/
class ProxyVpnThread(
vpnInterface: ParcelFileDescriptor,
proxyHost: String,
proxyPort: Int,
proxyPassDomains: ArrayList<String>? = null,
) : Thread("Vpn thread") {
companion object {
const val TAG = "ProxyVpnThread"
}
@Volatile
private var running = false
private val vpnReadChannel = FileInputStream(vpnInterface.fileDescriptor).channel
// 此VPN接收的来自上游服务器的数据包
private val vpnWriteStream = FileOutputStream(vpnInterface.fileDescriptor)
private val vpnPacketWriter = ClientPacketWriter(vpnWriteStream)
private val vpnPacketWriterThread = Thread(vpnPacketWriter)
// Background service & task for non-blocking socket
private val nioService = SocketNIODataService(vpnPacketWriter)
private val dataServiceThread = Thread(nioService, "Socket NIO thread")
private val manager = ConnectionManager.instance.apply {
//流量转发到代理地址
this.proxyAddress = InetSocketAddress(proxyHost, proxyPort)
this.proxyPassDomains = proxyPassDomains
}
private val handler = ConnectionHandler(manager, nioService, vpnPacketWriter)
private var currentThread: Thread? = null
override fun run() {
Log.i(TAG, "Vpn thread starting")
currentThread = currentThread()
dataServiceThread.start()
vpnPacketWriterThread.start()
val readBuffer = ByteBuffer.allocate(MAX_PACKET_LEN)
running = true
while (running) {
try {
val length = vpnReadChannel.read(readBuffer)
if (length > 0) {
try {
readBuffer.flip()
handler.handlePacket(readBuffer)
} catch (e: Exception) {
val errorMessage = (e.message ?: e.toString())
Log.e(TAG, errorMessage, e)
}
readBuffer.clear()
} else {
sleep(50)
}
} catch (e: InterruptedException) {
Log.i(TAG, "Sleep interrupted: " + e.message)
} catch (e: InterruptedIOException) {
Log.i(TAG, "Read interrupted: " + e.message)
} catch (e: Exception) {
val errorMessage = (e.message ?: e.toString())
Log.e(TAG, errorMessage, e)
if (!vpnReadChannel.isOpen) {
Log.i(TAG, "VPN read channel closed")
running = false
}
}
}
Log.i(TAG, "Vpn thread stop")
}
@Synchronized
fun stopThread() {
if (running) {
running = false
nioService.shutdown()
dataServiceThread.interrupt()
vpnPacketWriter.shutdown()
vpnPacketWriterThread.interrupt()
currentThread?.interrupt()
}
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/Tag.kt
================================================
package com.network.proxy.vpn
fun formatTag(tag: String): String {
return tag
}
val Any.TAG: String
get() {
return javaClass.name
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/socket/ClientPacketWriter.kt
================================================
package com.network.proxy.vpn.socket
import android.util.Log
import java.io.FileOutputStream
import java.io.IOException
import java.util.concurrent.BlockingDeque
import java.util.concurrent.LinkedBlockingDeque
import kotlin.concurrent.Volatile
class ClientPacketWriter(private val clientWriter: FileOutputStream) : Runnable {
companion object {
private const val TAG: String = "ClientPacketWriter"
private const val MAX_PACKET_LEN = 32767
}
@Volatile
private var shutdown = false
private val packetQueue: BlockingDeque<ByteArray> = LinkedBlockingDeque()
fun write(data: ByteArray) {
if (data.size > MAX_PACKET_LEN) throw Error("Packet too large")
packetQueue.addLast(data)
}
fun shutdown() {
this.shutdown = true
}
override fun run() {
while (!this.shutdown && clientWriter.channel.isOpen) {
try {
val data: ByteArray = this.packetQueue.take()
try {
this.clientWriter.write(data)
} catch (e: IOException) {
Log.e(TAG, "Error writing $shutdown data.length bytes to the VPN")
e.printStackTrace()
// this.packetQueue.addFirst(data) // Put the data back, so it's resent
Thread.sleep(10) // Add an arbitrary tiny pause, in case that helps
}
} catch (ignored: InterruptedException) {
}
}
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/socket/CloseableConnection.kt
================================================
package com.network.proxy.vpn.socket
import com.network.proxy.vpn.Connection
interface CloseableConnection {
/**
* 关闭连接
*/
fun closeConnection(connection: Connection)
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/socket/Constant.kt
================================================
package com.network.proxy.vpn.socket
object Constant {
const val MAX_RECEIVE_BUFFER_SIZE = 65535
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/socket/ProtectSocket.kt
================================================
package com.network.proxy.vpn.socket
import java.net.DatagramSocket
import java.net.Socket
interface ProtectSocket {
/**
* 保护Socket不受VPN连接的影响。保护后,通过该套接字发送的数据将直接进入底层网络,因此其流量不会通过VPN转发。
*/
fun protect(socket: Socket): Boolean
fun protect(socket: DatagramSocket): Boolean
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/socket/ProtectSocketHolder.kt
================================================
package com.network.proxy.vpn.socket
import java.net.DatagramSocket
import java.net.Socket
/**
* ProtectSocket的持有者,用于在VPNService中获取ProtectSocket的实例
*/
class ProtectSocketHolder {
companion object {
private var protectSocket: ProtectSocket? = null
fun setProtectSocket(protectSocket: ProtectSocket) {
this.protectSocket = protectSocket
}
fun getProtectSocket(): ProtectSocket? {
return protectSocket
}
fun protect(socket: Socket): Boolean {
return protectSocket?.protect(socket) ?: false
}
fun protect(socket: DatagramSocket): Boolean {
return protectSocket?.protect(socket) ?: false
}
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/socket/SocketChannelReader.java
================================================
package com.network.proxy.vpn.socket;
import androidx.annotation.NonNull;
import android.util.Log;
import com.network.proxy.vpn.Connection;
import com.network.proxy.vpn.TagKt;
import com.network.proxy.vpn.transport.protocol.IP4Header;
import com.network.proxy.vpn.transport.protocol.TCPHeader;
import com.network.proxy.vpn.transport.protocol.TCPPacketFactory;
import com.network.proxy.vpn.transport.protocol.UDPPacketFactory;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.AbstractSelectableChannel;
/**
* Takes a session, and reads all available upstream data back into it.
* Used by the NIO thread, and run synchronously as part of that non-blocking loop.
*/
class SocketChannelReader {
private final String TAG = TagKt.getTAG(this);
private final ClientPacketWriter writer;
public SocketChannelReader(ClientPacketWriter writer) {
this.writer = writer;
}
public void read(Connection connection) {
AbstractSelectableChannel channel = connection.getChannel();
if (channel instanceof SocketChannel) {
readTCP(connection);
} else if (channel instanceof DatagramChannel) {
readUDP(connection);
} else {
return;
}
// Resubscribe to reads, so that we're triggered again if more data arrives later.
connection.subscribeKey(SelectionKey.OP_READ);
if (connection.isAbortingConnection()) {
Log.d(TAG, "removing aborted connection -> " + connection);
connection.cancelKey();
if (channel instanceof SocketChannel) {
try {
SocketChannel socketChannel = (SocketChannel) channel;
if (socketChannel.isConnected()) {
socketChannel.close();
}
} catch (IOException e) {
Log.e(TAG, e.toString());
}
} else {
try {
DatagramChannel datagramChannel = (DatagramChannel) channel;
if (datagramChannel.isConnected()) {
datagramChannel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
connection.closeConnection();
}
}
private void readTCP(@NonNull Connection connection) {
if (connection.isAbortingConnection()) {
return;
}
SocketChannel channel = (SocketChannel) connection.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(Constant.MAX_RECEIVE_BUFFER_SIZE);
int len;
try {
do {
len = channel.read(buffer);
if (len > 0) { //-1 mean it reach the end of stream
sendToRequester(buffer, len, connection);
buffer.clear();
} else if (len == -1) {
// Log.d(TAG,"End of data from remote server, will send FIN to client");
Log.d(TAG, "send FIN to: " + connection);
sendFin(connection);
connection.setAbortingConnection(true);
}
} while (len > 0);
} catch (NotYetConnectedException e) {
Log.e(TAG, "socket not connected");
} catch (ClosedByInterruptException e) {
Log.e(TAG, "ClosedByInterruptException reading SocketChannel: " + e.getMessage());
} catch (ClosedChannelException e) {
Log.e(TAG, "ClosedChannelException reading SocketChannel: " + e.getMessage());
} catch (IOException e) {
Log.e(TAG, "Error reading data from SocketChannel: " + e.getMessage());
connection.setAbortingConnection(true);
}
}
private void sendToRequester(ByteBuffer buffer, int dataSize, @NonNull Connection connection) {
// Last piece of data is usually smaller than MAX_RECEIVE_BUFFER_SIZE. We use this as a
// trigger to set PSH on the resulting TCP packet that goes to the VPN.
connection.setHasReceivedLastSegment(dataSize < Constant.MAX_RECEIVE_BUFFER_SIZE);
buffer.limit(dataSize);
buffer.flip();
// TODO should allocate new byte array?
byte[] data = new byte[dataSize];
System.arraycopy(buffer.array(), 0, data, 0, dataSize);
connection.addReceivedData(data);
//pushing all data to vpn client
while (connection.hasReceivedData()) {
pushDataToClient(connection);
}
}
/**
* create packet data and send it to VPN client
*/
private void pushDataToClient(@NonNull Connection connection) {
if (!connection.hasReceivedData()) {
//no data to send
Log.d(TAG, "no data for vpn client");
}
IP4Header ipHeader = connection.getLastIpHeader();
TCPHeader tcpheader = connection.getLastTcpHeader();
// TODO What does 60 mean?
int max = connection.getMaxSegmentSize() - 60;
if (max < 1) {
max = 1024;
}
byte[] packetBody = connection.getReceivedData(max);
if (packetBody != null && packetBody.length > 0) {
long unAck = connection.getSendNext();
long nextUnAck = connection.getSendNext() + packetBody.length;
connection.setSendNext((int) nextUnAck);
//we need this data later on for retransmission
// connection.setUnackData(packetBody);
// connection.setResendPacketCounter(0);
byte[] data = TCPPacketFactory.createResponsePacketData(ipHeader,
tcpheader, packetBody, connection.getHasReceivedLastSegment(),
connection.getRecSequence(), (int) unAck,
connection.getTimestampSender(), connection.getTimestampReplyTo());
writer.write(data);
}
}
private void sendFin(Connection connection) {
final IP4Header ipHeader = connection.getLastIpHeader();
final TCPHeader tcpheader = connection.getLastTcpHeader();
final byte[] data = TCPPacketFactory.INSTANCE.createFinData(ipHeader, tcpheader,
connection.getRecSequence(), connection.getSendNext(),
connection.getTimestampSender(), connection.getTimestampReplyTo());
writer.write(data);
}
private void readUDP(Connection connection) {
DatagramChannel channel = (DatagramChannel) connection.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(Constant.MAX_RECEIVE_BUFFER_SIZE);
int len;
try {
do {
if (connection.isAbortingConnection()) {
break;
}
len = channel.read(buffer);
if (len > 0) {
buffer.limit(len);
buffer.flip();
//create UDP packet
byte[] data = new byte[len];
System.arraycopy(buffer.array(), 0, data, 0, len);
byte[] packetData = UDPPacketFactory.createResponsePacket(
connection.getLastIpHeader(), connection.getLastUdpHeader(), data);
//write to client
writer.write(packetData);
buffer.clear();
}
} while (len > 0);
} catch (NotYetConnectedException ex) {
Log.e(TAG, "failed to read from unconnected UDP socket");
} catch (IOException e) {
Log.e(TAG, "Failed to read from UDP socket, aborting connection");
connection.setAbortingConnection(true);
}
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/socket/SocketChannelWriter.java
================================================
package com.network.proxy.vpn.socket;
import androidx.annotation.NonNull;
import android.util.Log;
import com.network.proxy.vpn.Connection;
import com.network.proxy.vpn.TagKt;
import com.network.proxy.vpn.transport.protocol.TCPPacketFactory;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.AbstractSelectableChannel;
/**
* Takes a VPN session, and writes all received data from it to the upstream channel.
* <p>
* If any writes fail, it resubscribes to OP_WRITE, and tries again next time
* that fires (as soon as the channel is ready for more data).
* <p>
* Used by the NIO thread, and run synchronously as part of that non-blocking loop.
*/
public class SocketChannelWriter {
private final String TAG = TagKt.getTAG(this);
private final ClientPacketWriter writer;
SocketChannelWriter(ClientPacketWriter writer) {
this.writer = writer;
}
public void write(@NonNull Connection connection) {
AbstractSelectableChannel channel = connection.getChannel();
if (channel instanceof SocketChannel) {
writeTCP(connection);
} else if(channel instanceof DatagramChannel) {
writeUDP(connection);
} else {
// We only ever create TCP & UDP channels, so this should never happen
throw new IllegalArgumentException("Unexpected channel type: " + channel);
}
if (connection.isAbortingConnection()) {
Log.d(TAG,"removing aborted connection -> " + connection);
connection.cancelKey();
if (channel instanceof SocketChannel) {
try {
SocketChannel socketChannel = (SocketChannel) channel;
if (socketChannel.isConnected()) {
socketChannel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
try {
DatagramChannel datagramChannel = (DatagramChannel) channel;
if (datagramChannel.isConnected()) {
datagramChannel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
connection.closeConnection();
}
}
private void writeUDP(Connection connection) {
try {
writePendingData(connection);
// Date dt = new Date();
// connection.connectionStartTime = dt.getTime();
}catch(NotYetConnectedException ex2){
connection.setAbortingConnection(true);
Log.e(TAG,"Error writing to unconnected-UDP server, will abort current connection: "+ex2.getMessage());
} catch (IOException e) {
connection.setAbortingConnection(true);
e.printStackTrace();
Log.e(TAG,"Error writing to UDP server, will abort connection: "+e.getMessage());
}
}
private void writeTCP(Connection connection) {
try {
writePendingData(connection);
} catch (NotYetConnectedException ex) {
Log.e(TAG,"failed to write to unconnected socket: " + ex.getMessage());
} catch (IOException e) {
Log.e(TAG,"Error writing to server: " + e);
//close connection with vpn client
byte[] rstData = TCPPacketFactory.INSTANCE.createRstData(
connection.getLastIpHeader(), connection.getLastTcpHeader(), 0);
writer.write(rstData);
//remove session
Log.e(TAG,"failed to write to remote socket, aborting connection");
connection.setAbortingConnection(true);
}
}
private void writePendingData(Connection connection) throws IOException {
if (!connection.hasDataToSend()) return;
AbstractSelectableChannel channel = connection.getChannel();
byte[] data = connection.getSendingData();
ByteBuffer buffer = ByteBuffer.allocate(data.length);
buffer.put(data);
buffer.flip();
while (buffer.hasRemaining()) {
int bytesWritten = channel instanceof SocketChannel
? ((SocketChannel) channel).write(buffer)
: ((DatagramChannel) channel).write(buffer);
if (bytesWritten == 0) {
break;
}
}
if (buffer.hasRemaining()) {
// The channel's own buffer is full, so we have to save this for later.
Log.i(TAG, buffer.remaining() + " bytes unwritten for " + channel);
// Put the remaining data from the buffer back into the session
connection.setSendingData(buffer.compact());
// Subscribe to WRITE events, so we know when this is ready to resume.
connection.subscribeKey(SelectionKey.OP_WRITE);
} else {
// All done, all good -> wait until the next TCP PSH / UDP packet
connection.setDataForSendingReady(false);
// We don't need to know about WRITE events any more, we've written all our data.
// This is safe from races with new data, due to the session lock in NIO.
connection.unsubscribeKey(SelectionKey.OP_WRITE);
}
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/socket/SocketNIODataService.java
================================================
package com.network.proxy.vpn.socket;
import android.util.Log;
import com.network.proxy.vpn.Connection;
import com.network.proxy.vpn.TagKt;
import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.util.Iterator;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* A service that single-threadedly processes the events around our session connections,
* entirely via non-blocking NIO.
* <p>
* It uses a Selector that fires on outgoing socket events (connected, readable, writable),
* handles the resulting operations, and keeps those subscriptions up to date.
*/
public class SocketNIODataService implements Runnable {
private final String TAG = TagKt.getTAG(this);
private final ReentrantLock nioSelectionLock = new ReentrantLock();
private final ReentrantLock nioHandlingLock = new ReentrantLock();
private final Selector selector = Selector.open();
private final SocketChannelReader reader;
private final SocketChannelWriter writer;
private volatile boolean shutdown = false;
public SocketNIODataService(ClientPacketWriter clientPacketWriter) throws IOException {
reader = new SocketChannelReader(clientPacketWriter);
writer = new SocketChannelWriter(clientPacketWriter);
}
@Override
public void run() {
Log.d(TAG,"SocketNIODataService starting in background...");
runTask();
}
public void registerSession(Connection connection) throws ClosedChannelException {
AbstractSelectableChannel channel = connection.getChannel();
boolean isConnected = channel instanceof DatagramChannel
? ((DatagramChannel) channel).isConnected()
: ((SocketChannel) channel).isConnected();
// Log.i(TAG, "Registering new session: " + session);
Lock selectorLock = lockSelector(selector);
try {
SelectionKey selectionKey = channel.register(selector,
isConnected
? SelectionKey.OP_READ
: SelectionKey.OP_CONNECT
);
connection.setSelectionKey(selectionKey);
selectionKey.attach(connection);
// Log.d(TAG, "Registered selector successfully");
} finally {
selectorLock.unlock();
}
}
private Lock lockSelector(Selector selector) {
boolean gotSelectionLock = nioSelectionLock.tryLock();
if (gotSelectionLock) return nioSelectionLock;
nioHandlingLock.lock(); // Ensure the NIO thread can't do anything on wakeup
selector.wakeup();
nioSelectionLock.lock(); // Actually get the lock we want
nioHandlingLock.unlock(); // Release the handling lock, which we no longer care about
return nioSelectionLock;
}
/**
* If the selector is currently select()ing, wake it up (e.g. to register changes to
* interestOps). If it's not (and so it probably will select() very soon anyway) do nothing.
* This is designed to be run after changing readyOps, to ensure the new ops get monitored
* immediately (and fire immediately, if already ready). Without this, that blocks.
*/
public void refreshSelect(Connection connection) {
boolean gotLock = nioSelectionLock.tryLock();
if (!gotLock) {
connection.getSelectionKey().selector().wakeup();
} else {
nioSelectionLock.unlock();
}
}
/**
* Shut down the NIO thread
*/
public void shutdown(){
this.shutdown = true;
selector.wakeup();
}
private void runTask(){
Log.i(TAG, "NIO selector is running...");
while(!shutdown){
try {
nioSelectionLock.lockInterruptibly();
selector.select();
} catch (IOException e) {
Log.e(TAG,"Error in Selector.select(): " + e.getMessage());
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Log.e(TAG, e.toString());
}
continue;
} catch (InterruptedException ex) {
Log.i(TAG, "Select() interrupted");
} finally {
if (nioSelectionLock.isHeldByCurrentThread()) {
nioSelectionLock.unlock();
}
}
if (shutdown) {
break;
}
// A lock here makes it possible to reliably grab the selection lock above
nioHandlingLock.lock();
try {
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
Connection connection = ((Connection) key.attachment());
synchronized (connection) { // Sessions are locked during processing (no VPN data races)
try {
processSelectionKey(key);
} catch (IOException e) {
synchronized (key) {
key.cancel();
}
}
}
iterator.remove();
if (shutdown) {
break;
}
}
} finally {
nioHandlingLock.unlock();
}
}
Log.i(TAG, "NIO selector shutdown");
}
private void processSelectionKey(SelectionKey key) throws IOException {
if (!key.isValid()) {
Log.d(TAG,"Invalid SelectionKey");
return;
}
SelectableChannel channel = key.channel();
Connection connection = ((Connection) key.attachment());
if (connection == null) {
Log.w(TAG, "Key fired with no session attached");
return;
}
if (channel instanceof SocketChannel && !connection.isConnected() && key.isConnectable()) {
SocketChannel socketChannel = (SocketChannel) channel;
if (socketChannel.isConnectionPending()) {
boolean connected = socketChannel.finishConnect();
connection.setConnected(connected);
} else {
throw new IllegalStateException("TCP channels must either be connected or pending connection");
}
}
if (isConnected(channel)) {
processConnectedSelection(key, connection);
}
}
private boolean isConnected(SelectableChannel channel) {
if (channel instanceof DatagramChannel) {
return ((DatagramChannel) channel).isConnected();
} else if (channel instanceof SocketChannel) {
return ((SocketChannel) channel).isConnected();
} else {
throw new IllegalArgumentException("isConnected on unexpected channel type: " + channel);
}
}
private void processConnectedSelection(SelectionKey key, Connection connection) {
// Whilst connected, we always want READ and not CONNECT events
connection.unsubscribeKey(SelectionKey.OP_CONNECT);
connection.subscribeKey(SelectionKey.OP_READ);
processSelectorRead(key, connection);
processPendingWrite(key, connection);
}
private void processSelectorRead(SelectionKey selectionKey, Connection connection) {
boolean canRead;
synchronized (selectionKey) {
// There's a race here that requires a lock, as isReadable requires isValid
canRead = selectionKey.isValid() && selectionKey.isReadable();
}
if (canRead) reader.read(connection);
}
private void processPendingWrite(SelectionKey selectionKey, Connection connection) {
// Nothing to write? Skip this entirely, and make sure we're not subscribed
if (!connection.hasDataToSend() || !connection.isDataForSendingReady()) {
connection.unsubscribeKey(SelectionKey.OP_WRITE);
return;
}
boolean canWrite;
synchronized (selectionKey) {
// There's a race here that requires a lock, as isReadable requires isValid
canWrite = selectionKey.isValid() && selectionKey.isWritable();
}
if (canWrite) {
connection.unsubscribeKey(SelectionKey.OP_WRITE);
writer.write(connection); // This will resubscribe to OP_WRITE if it can't complete
}
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/transport/Packet.kt
================================================
package com.network.proxy.vpn.transport
import com.network.proxy.vpn.transport.protocol.IP4Header
import com.network.proxy.vpn.transport.protocol.TransportHeader
class Packet(var ipHeader: IP4Header, var transportHeader: TransportHeader, var buffer: ByteArray) {
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/transport/icmp/ICMPPacket.java
================================================
package com.network.proxy.vpn.transport.icmp;
import androidx.annotation.NonNull;
public class ICMPPacket {
// Two ICMP packets we can handle: simple ping & pong
public static final byte ECHO_REQUEST_TYPE = 8;
public static final byte ECHO_SUCCESS_TYPE = 0;
// One very common packet we ignore: connection rejection. Unclear why this happens,
// random incoming connections that the phone tries to reply to? Nothing we can do though,
// as we can't forward ICMP onwards, and we can't usefully respond or react.
public static final byte DESTINATION_UNREACHABLE_TYPE = 3;
public final byte type;
final byte code; // 0 for request, 0 for success, 0 - 15 for error subtypes
final int checksum;
final int identifier;
final int sequenceNumber;
final byte[] data;
ICMPPacket(
int type,
int code,
int checksum,
int identifier,
int sequenceNumber,
byte[] data
) {
this.type = (byte) type;
this.code = (byte) code;
this.checksum = checksum;
this.identifier = identifier;
this.sequenceNumber = sequenceNumber;
this.data = data;
}
@NonNull
public String toString() {
return "ICMP packet type " + type + "/" + code + " id:" + identifier +
" seq:" + sequenceNumber + " and " + data.length + " bytes of data";
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/transport/icmp/ICMPPacketFactory.java
================================================
package com.network.proxy.vpn.transport.icmp;
import androidx.annotation.NonNull;
import com.network.proxy.vpn.transport.protocol.IP4Header;
import com.network.proxy.vpn.util.PacketUtil;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
public class ICMPPacketFactory {
public static ICMPPacket parseICMPPacket(@NonNull ByteBuffer stream) {
final byte type = stream.get();
final byte code = stream.get();
final int checksum = stream.getShort();
final int identifier = stream.getShort();
final int sequenceNumber = stream.getShort();
final byte[] data = new byte[stream.remaining()];
stream.get(data);
return new ICMPPacket(type, code, checksum, identifier, sequenceNumber, data);
}
public static ICMPPacket buildSuccessPacket(ICMPPacket requestPacket) {
return new ICMPPacket(
0,
0,
0,
requestPacket.identifier,
requestPacket.sequenceNumber,
requestPacket.data
);
}
public static byte[] packetToBuffer(IP4Header ipHeader, ICMPPacket packet) {
byte[] ipData = ipHeader.toBytes();
ByteArrayOutputStream icmpDataBuffer = new ByteArrayOutputStream();
icmpDataBuffer.write(packet.type);
icmpDataBuffer.write(packet.code);
icmpDataBuffer.write(asShortBytes(0 /* checksum placeholder */), 0, 2);
if (packet.type == ICMPPacket.ECHO_REQUEST_TYPE || packet.type == ICMPPacket.ECHO_SUCCESS_TYPE) {
icmpDataBuffer.write(asShortBytes(packet.identifier), 0, 2);
icmpDataBuffer.write(asShortBytes(packet.sequenceNumber), 0, 2);
byte[] extraData = packet.data;
icmpDataBuffer.write(extraData, 0, extraData.length);
} else {
throw new IllegalArgumentException("Can't serialize unrecognized ICMP packet type");
}
byte[] icmpPacketData = icmpDataBuffer.toByteArray();
byte[] checksum = PacketUtil.INSTANCE.calculateChecksum(icmpPacketData, 0, icmpPacketData.length);
ByteBuffer resultBuffer = ByteBuffer.allocate(ipData.length + icmpPacketData.length);
resultBuffer.put(ipData);
resultBuffer.put(icmpPacketData);
// Replace the checksum placeholder
resultBuffer.position(ipData.length + 2);
resultBuffer.put(checksum);
resultBuffer.position(0);
byte[] result = new byte[resultBuffer.remaining()];
resultBuffer.get(result);
return result;
}
private static byte[] asShortBytes(int value) {
return ByteBuffer.allocate(2).putShort((short) value).array();
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/transport/protocol/IP4Header.kt
================================================
package com.network.proxy.vpn.transport.protocol
import android.util.Log
import java.nio.ByteBuffer
import java.nio.ByteOrder
/**
* IPv4报头的数据结构。
*/
data class IP4Header(
var ipVersion: Byte = 0, //对于IPv4,其值为4(因此命名为IPv4)。 4bit
private var internetHeaderLength: Byte = 0, //头部长度 4bit
private var diffTypeOfService: Byte, //差分服务代码点 =>6位
private var ecn: Byte = 0, //显式拥塞通知(ECN)
var totalLength: Int = 0, //此IP数据包的总长度 16bit
var identification: Int = 0, //主要用于唯一标识单个IP数据报的片段组。 16bit
private var mayFragment: Boolean, // 1bit 用于指示数据报是否可以分段。
private var lastFragment: Boolean, // 1bit 用于指示数据报是否是片段中的最后一个。
var fragmentOffset: Short = 0, //13bit,指定特定片段相对于原始未分段的IP数据报的开始的偏移量。
private var timeToLive: Byte = 0, //用于防止数据报持续存在。8bit
var protocol: Byte = 0, //定义IP数据报的数据部分中使用的协议。 8bit
var headerChecksum: Int = 0, //用于对头部进行错误检查的16位字段。 16bit
var sourceIP: Int = 0, //发送者的IPv4地址。 32bit
var destinationIP: Int = 0 //接收者的IPv4地址。 32bit
) {
//用于控制或识别片段的3比特字段。
//bit 0: 保留;必须为零
//bit 1: Don't Fragment (DF)
//bit 2: More Fragments (MF)
private var flag: Byte = initFlag()
private fun initFlag(): Byte {
var initFlag = 0
if (mayFragment) {
initFlag = 0x40
}
if (lastFragment) {
initFlag = (initFlag or 0x20)
}
return initFlag.toByte()
}
fun setMayFragment(mayFragment: Boolean) {
this.mayFragment = mayFragment
flag = if (mayFragment) {
(flag.toInt() or 0x40).toByte()
} else {
(flag.toInt() and 0xBF).toByte()
}
}
fun getIPHeaderLength(): Int {
return internetHeaderLength * 4
}
fun copy(): IP4Header {
return IP4Header(
ipVersion, internetHeaderLength, diffTypeOfService, ecn, totalLength, identification,
mayFragment, lastFragment, fragmentOffset, timeToLive, protocol, headerChecksum,
sourceIP, destinationIP
)
}
fun toBytes(): ByteArray {
val buffer = ByteBuffer.allocate(getIPHeaderLength())
buffer.order(ByteOrder.BIG_ENDIAN)
val versionAndHeaderLength = (ipVersion.toInt() shl 4) + internetHeaderLength
buffer.put(versionAndHeaderLength.toByte())
val typeOfService: Byte = (diffTypeOfService.toInt() shl 2 and (ecn
.toInt() and 0xFF)).toByte()
buffer.put(typeOfService)
buffer.putShort(totalLength.toShort())
buffer.putShort(identification.toShort())
//组合标志和部分片段偏移
buffer.put((fragmentOffset.toInt() shr 8 and 0x1F or flag.toInt()).toByte())
buffer.put(fragmentOffset.toByte())
buffer.put(timeToLive)
buffer.put(protocol)
buffer.putShort(headerChecksum.toShort())
buffer.putInt(sourceIP)
buffer.putInt(destinationIP)
return buffer.array()
}
}
object IPPacketFactory {
private const val IP4_HEADER_SIZE = 20
private const val IP4_VERSION = 0x04
/**
* 从给定的ByteBuffer流创建IPv4标头
*/
fun createIP4Header(buffer: ByteBuffer): IP4Header? {
if (buffer.remaining() < IP4_HEADER_SIZE) {
throw IllegalArgumentException("IP header byte array must have at least $IP4_HEADER_SIZE bytes")
}
val versionAndHeaderLength: Byte = buffer.get()
val ipVersion = (versionAndHeaderLength.toInt() shr 4).toByte()
if (ipVersion.toInt() != IP4_VERSION) {
Log.e("IPPacketFactory", "Invalid IP version $ipVersion")
return null
}
val internetHeaderLength = (versionAndHeaderLength.toInt() and 0x0F).toByte()
val typeOfService = buffer.get().toInt()
val diffTypeOfService: Byte = (typeOfService shr 2).toByte();
val ecn: Byte = (typeOfService and 0x03).toByte()
val totalLength: Int = buffer.getShort().toInt()
val identification: Int = buffer.getShort().toInt()
val flagsAndFragmentOffset: Short = buffer.getShort()
val mayFragment = flagsAndFragmentOffset.toInt() and 0x4000 != 0
val lastFragment = flagsAndFragmentOffset.toInt() and 0x2000 != 0
val fragmentOffset = (flagsAndFragmentOffset.toInt() and 0x1FFF).toShort()
val timeToLive: Byte = buffer.get()
val protocol: Byte = buffer.get()
val checksum: Int = buffer.getShort().toInt()
val sourceIp: Int = buffer.getInt()
val desIp: Int = buffer.getInt()
if (internetHeaderLength > 5) {
// drop the IP option
for (i in 0 until (internetHeaderLength - 5)) {
buffer.getInt()
}
}
return IP4Header(
ipVersion, internetHeaderLength, diffTypeOfService, ecn, totalLength, identification,
mayFragment, lastFragment, fragmentOffset, timeToLive, protocol, checksum,
sourceIp, desIp
)
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/transport/protocol/TCPHeader.kt
================================================
package com.network.proxy.vpn.transport.protocol
import java.nio.ByteBuffer
import java.nio.ByteOrder
/**
* TCP报头的数据结构。
*/
class TCPHeader(
private var sourcePort: Int = 0, //源端口号 16bit
private var destinationPort: Int = 0, //目的端口号 16bit
var sequenceNumber: Long = 0, //序列号 32bit
var ackNumber: Long = 0, //确认号 32bit
var dataOffset: Int = 0, //数据偏移4bit
var isNS: Boolean = false, //ECN-nonce concealment protection (experimental: see RFC 3540)
var flags: Int = 0, //标志位 9bit
var windowSize: Int = 0, //窗口大小 16bit
var checksum: Int = 0, //校验和 16bit
private var urgentPointer: Int = 0, //紧急指针 16bit
var options: ByteArray? = null //选项
) : TransportHeader {
//options
var maxSegmentSize: Short = 0
private var windowScale: Byte = 0
private var isSelectiveAckPermitted = false
var timeStampSender = 0
var timeStampReplyTo = 0
companion object {
private const val END_OF_OPTIONS_LIST: Byte = 0
private const val NO_OPERATION: Byte = 1
private const val MAX_SEGMENT_SIZE: Byte = 2
private const val WINDOW_SCALE: Byte = 3
private const val SELECTIVE_ACK_PERMITTED: Byte = 4
private const val TIME_STAMP: Byte = 8
}
fun isSYN(): Boolean {
return flags and 0x02 != 0
}
fun isFIN(): Boolean {
return flags and 0x01 != 0
}
fun isRST(): Boolean {
return flags and 0x04 != 0
}
fun isPSH(): Boolean {
return flags and 0x08 != 0
}
fun isACK(): Boolean {
return flags and 0x10 != 0
}
fun isURG(): Boolean {
return flags and 0x20 != 0
}
fun isECE(): Boolean {
return flags and 0x40 != 0
}
fun isCWR(): Boolean {
return flags and 0x80 != 0
}
fun setIsRST(isRST: Boolean) {
flags = if (isRST) {
(flags or 0x04)
} else {
(flags and 0xFB)
}
}
fun setIsSYN(isSYN: Boolean) {
flags = if (isSYN) {
(flags or 0x02)
} else {
(flags and 0xFD)
}
}
fun setIsFIN(isFIN: Boolean) {
flags = if (isFIN) {
(flags or 0x01)
} else {
(flags and 0xFE)
}
}
fun setIsPSH(isPSH: Boolean) {
flags = if (isPSH) {
(flags or 0x08)
} else {
(flags and 0xF7)
}
}
fun setIsACK(isACK: Boolean) {
flags = if (isACK) {
(flags or 0x10)
} else {
(flags and 0xEF)
}
}
fun getTCPHeaderLength(): Int {
return dataOffset * 4
}
fun toBytes(): ByteArray {
val tcpHeaderLength = getTCPHeaderLength()
val tcpHeader = ByteArray(tcpHeaderLength)
val byteBuffer = ByteBuffer.wrap(tcpHeader)
byteBuffer.order(ByteOrder.BIG_ENDIAN)
byteBuffer.putShort(sourcePort.toShort())
byteBuffer.putShort(destinationPort.toShort())
byteBuffer.putInt(sequenceNumber.toInt())
byteBuffer.putInt(ackNumber.toInt())
//is ns and data offset
byteBuffer.put(((dataOffset shl 4) and 0xF0 or (if (isNS) 0x1 else 0x0)).toByte())
byteBuffer.put(flags.toByte())
byteBuffer.putShort(windowSize.toShort())
byteBuffer.putShort(checksum.toShort())
byteBuffer.putShort(urgentPointer.toShort())
// encodeTcpOptions()?.let {
// byteBuffer.put(it)
// }
return tcpHeader
}
fun copy(): TCPHeader {
return TCPHeader(
sourcePort, destinationPort, sequenceNumber, ackNumber,
dataOffset, isNS, flags, windowSize, checksum, urgentPointer,
options
)
}
private fun handleTcpOptions() {
if (options == null) {
return
}
var index = 0
val packet = ByteBuffer.wrap(options!!)
val optionsSize = options!!.size
while (index < optionsSize) {
val optionKind = packet.get()
index++
if (optionKind == END_OF_OPTIONS_LIST || optionKind == NO_OPERATION) {
continue
}
val size = packet.get()
index++
when (optionKind) {
MAX_SEGMENT_SIZE -> {
maxSegmentSize = packet.getShort()
index += 2
}
WINDOW_SCALE -> {
windowScale = packet.get()
index++
}
SELECTIVE_ACK_PERMITTED -> isSelectiveAckPermitted = true
TIME_STAMP -> {
timeStampSender = packet.getInt()
timeStampReplyTo = packet.getInt()
index += 8
}
else -> {
skipRemainingOptions(packet, size.toInt())
index = index + size - 2
}
}
}
}
private fun skipRemainingOptions(packet: ByteBuffer, size: Int) {
for (i in 2 until size) {
packet.get()
}
}
override fun getSourcePort(): Int {
return sourcePort
}
override fun getDestinationPort(): Int {
return destinationPort
}
fun setSourcePort(sourcePort: Int) {
this.sourcePort = sourcePort
}
fun setDestinationPort(destinationPort: Int) {
this.destinationPort = destinationPort
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/transport/protocol/TCPPacketFactory.kt
================================================
package com.network.proxy.vpn.transport.protocol
import com.network.proxy.vpn.transport.Packet
import com.network.proxy.vpn.util.PacketUtil
import java.nio.ByteBuffer
import java.util.concurrent.ThreadLocalRandom
object TCPPacketFactory {
private const val TCP_HEADER_LENGTH = 20
/**
* 从tcp报文创建tcpHeader
*/
@JvmStatic
fun createTCPHeader(byteBuffer: ByteBuffer): TCPHeader {
if (byteBuffer.remaining() < TCP_HEADER_LENGTH) {
throw IllegalArgumentException("Invalid TCP Header Length")
}
val sourcePort: Int = byteBuffer.getShort().toInt() and 0xFFFF
val destinationPort: Int = byteBuffer.getShort().toInt() and 0xFFFF
val sequenceNumber: Long = byteBuffer.getInt().toLong()
val ackNumber: Long = byteBuffer.getInt().toLong()
val dataOffsetAndReserved = byteBuffer.get()
val dataOffset = (dataOffsetAndReserved.toInt() and 0xF0) shr 4
val isNs: Boolean = dataOffsetAndReserved.toInt() and 0x1 > 0x0
val flags = byteBuffer.get().toInt()
val window = byteBuffer.short.toInt()
val checksum = byteBuffer.short.toInt()
val urgentPointer = byteBuffer.short.toInt()
var optionsAndPadding: ByteArray? = null
val optionsSize = dataOffset - 5
if (optionsSize > 0) {
optionsAndPadding = ByteArray(optionsSize * 4)
byteBuffer.get(optionsAndPadding, 0, optionsSize * 4)
}
return TCPHeader(
sourcePort, destinationPort, sequenceNumber, ackNumber,
dataOffset, isNs, flags, window, checksum, urgentPointer, optionsAndPadding
)
}
/**
* 创建带有RST标志的数据包,以便在需要重置时发送到客户端。
*/
fun createRstData(ipHeader: IP4Header, tcpHeader: TCPHeader, dataLength: Int): ByteArray {
val ip = ipHeader.copy()
val tcp = tcpHeader.copy()
var ackNumber: Long = 0
var seqNumber: Long = 0
if (tcp.ackNumber > 0) {
seqNumber = tcp.ackNumber
} else {
ackNumber = tcp.sequenceNumber + dataLength
}
tcp.ackNumber = ackNumber
tcp.sequenceNumber = seqNumber
//将IP从源翻转到目标
flipIp(ip, tcp)
ip.identification = 0
tcp.flags = 0
tcp.isNS = false
tcp.setIsRST(true)
tcp.dataOffset = 5
tcp.options = null
tcp.windowSize = 0
//重新计算IP长度
val totalLength = ip.getIPHeaderLength() + tcp.getTCPHeaderLength()
ip.totalLength = totalLength
return createPacketData(ip, tcp, null)
}
/**
* 创建数据包数据以发送回客户端
*/
@JvmStatic
fun createResponsePacketData(
ipHeader: IP4Header, tcpHeader: TCPHeader, packetData: ByteArray?, isPsh: Boolean,
ackNumber: Long, seqNumber: Long, timeSender: Int, timeReplyTo: Int
): ByteArray {
val ip = ipHeader.copy()
val tcp = tcpHeader.copy()
flipIp(ip, tcp)
tcp.ackNumber = ackNumber
tcp.sequenceNumber = seqNumber
ip.identification = PacketUtil.getPacketId()
//总是发送ACK
//ACK is always sent
tcp.setIsACK(true)
tcp.setIsSYN(false)
tcp.setIsPSH(isPsh)
tcp.setIsFIN(false)
tcp.timeStampSender = timeSender
tcp.timeStampReplyTo = timeReplyTo
tcp.dataOffset = 5
tcp.options = null
var totalLength = ip.getIPHeaderLength() + tcp.getTCPHeaderLength()
if (packetData != null) {
totalLength += packetData.size
}
ip.totalLength = totalLength
return createPacketData(ip, tcp, packetData)
}
/**
* 向客户端确认服务器已收到请求。
*/
@JvmStatic
fun createResponseAckData(
ipHeader: IP4Header, tcpHeader: TCPHeader, ackToClient: Long
): ByteArray {
val ip = ipHeader.copy()
val tcp = tcpHeader.copy()
flipIp(ip, tcp)
val seqNumber = tcp.ackNumber
tcp.ackNumber = ackToClient
tcp.sequenceNumber = seqNumber
ip.identification = PacketUtil.getPacketId()
//ACK
tcp.setIsACK(true)
tcp.setIsSYN(false)
tcp.setIsPSH(false)
tcp.setIsFIN(false)
tcp.dataOffset = 5
tcp.options = null
ip.totalLength = ip.getIPHeaderLength() + tcp.getTCPHeaderLength()
return createPacketData(ip, tcp, null)
}
//将IP从源翻转到目标
private fun flipIp(ip: IP4Header, tcp: TCPHeader) {
val sourceIp = ip.destinationIP
val destIp = ip.sourceIP
val sourcePort = tcp.getDestinationPort()
val destPort = tcp.getSourcePort()
ip.destinationIP = destIp
ip.sourceIP = sourceIp
tcp.setDestinationPort(destPort)
tcp.setSourcePort(sourcePort)
}
/**
* 通过写回客户端流创建SYN-ACK数据包数据
*/
fun createSynAckPacketData(ipHeader: IP4Header, tcpHeader: TCPHeader): Packet {
val ip = ipHeader.copy()
val tcp = tcpHeader.copy()
flipIp(ip, tcp)
//ack = received sequence + 1
val ackNumber = tcpHeader.sequenceNumber + 1
tcp.ackNumber = ackNumber
//服务器生成的初始序列号
val seqNumber = ThreadLocalRandom.current().nextLong(0, 100000)
tcp.sequenceNumber = seqNumber
//SYN-ACK
tcp.setIsACK(true)
tcp.setIsSYN(true)
tcp.timeStampReplyTo = tcp.timeStampSender
tcp.timeStampSender = PacketUtil.currentTime
tcp.dataOffset = 5
tcp.options = null
ip.totalLength = ip.getIPHeaderLength() + tcp.getTCPHeaderLength()
return Packet(ip, tcp, createPacketData(ip, tcp, null))
}
/**
* 创建发送到客户端的FIN-ACK
*/
fun createFinAckData(
ipHeader: IP4Header, tcpHeader: TCPHeader, ackToClient: Long,
seqToClient: Long, isFin: Boolean, isAck: Boolean
): ByteArray {
val ip = ipHeader.copy()
val tcp = tcpHeader.copy()
flipIp(ip, tcp)
tcp.ackNumber = ackToClient
tcp.sequenceNumber = seqToClient
ip.identification = PacketUtil.getPacketId()
//ACK
tcp.setIsACK(isAck)
tcp.setIsSYN(false)
tcp.setIsPSH(false)
tcp.setIsFIN(isFin)
tcp.dataOffset = 5
tcp.options = null
ip.totalLength = ip.getIPHeaderLength() + tcp.getTCPHeaderLength()
return createPacketData(ip, tcp, null)
}
fun createFinData(
ip: IP4Header, tcp: TCPHeader, ackNumber: Long, seqNumber: Long,
timeSender: Int, timeReplyTo: Int
): ByteArray {
//将IP从源翻转到目标
flipIp(ip, tcp)
tcp.ackNumber = ackNumber
tcp.sequenceNumber = seqNumber
ip.identification = PacketUtil.getPacketId()
tcp.timeStampReplyTo = timeReplyTo
tcp.timeStampSender = timeSender
tcp.flags = 0
tcp.isNS = false
tcp.setIsACK(true)
tcp.setIsFIN(true)
tcp.dataOffset = 5
tcp.options = null
//窗口大小应为零
tcp.windowSize = 0
ip.totalLength = ip.getIPHeaderLength() + tcp.getTCPHeaderLength()
return createPacketData(ip, tcp, null)
}
/**
* 从tcpHeader创建tcp报文
*/
private fun createPacketData(ipHeader: IP4Header, tcpHeader: TCPHeader, data: ByteArray?):
ByteArray {
val dataLength = data?.size ?: 0
val buffer =
ByteBuffer.allocate(ipHeader.getIPHeaderLength() + tcpHeader.getTCPHeaderLength() + dataLength)
val ipBuffer = ipHeader.toBytes()
val tcpBuffer = tcpHeader.toBytes()
buffer.put(ipBuffer)
buffer.put(tcpBuffer)
data?.let { buffer.put(it) }
val zero = byteArrayOf(0, 0)
//计算前先将校验和清零
buffer.position(10)
buffer.put(zero)
val ipChecksum = PacketUtil.calculateChecksum(buffer.array(), 0, ipBuffer.size)
buffer.position(10)
buffer.put(ipChecksum)
val tcpStart = ipBuffer.size
buffer.position(tcpStart + 16)
buffer.put(zero)
val tcpChecksum = PacketUtil.calculateTCPHeaderChecksum(
buffer.array(), tcpStart, tcpBuffer.size + dataLength,
ipHeader.destinationIP, ipHeader.sourceIP
)
//将新的校验和写回阵列
buffer.position(tcpStart + 16)
buffer.put(tcpChecksum)
return buffer.array()
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/transport/protocol/TransportHeader.kt
================================================
package com.network.proxy.vpn.transport.protocol
interface TransportHeader {
fun getSourcePort(): Int
fun getDestinationPort(): Int
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/transport/protocol/UDPHeader.kt
================================================
package com.network.proxy.vpn.transport.protocol
import com.network.proxy.vpn.util.PacketUtil
import java.nio.ByteBuffer
/**
* UDP报头的数据结构。
*/
data class UDPHeader(
var sourcePort: Int = 0, //源端口号 16bit
var destinationPort: Int = 0, //目的端口号 16bit
var length: Int = 0, //UDP数据报长度 16bit
var checksum: Int = 0 //校验和 16bit
)
object UDPPacketFactory {
@JvmStatic
fun createUDPHeader(stream: ByteBuffer): UDPHeader {
require(stream.remaining() >= 8) { "Minimum UDP header is 8 bytes." }
val srcPort = stream.getShort().toInt() and 0xffff
val destPort = stream.getShort().toInt() and 0xffff
val length = stream.getShort().toInt() and 0xffff
val checksum = stream.getShort().toInt()
return UDPHeader(srcPort, destPort, length, checksum)
}
/**
* 创建用于响应vpn客户端的数据包
*/
@JvmStatic
fun createResponsePacket(ip: IP4Header, udp: UDPHeader, packetData: ByteArray?): ByteArray {
val buffer: ByteArray
var udpLen = 8
if (packetData != null) {
udpLen += packetData.size
}
val srcPort = udp.destinationPort
val destPort = udp.sourcePort
val ipHeader = ip.copy()
val srcIp = ip.destinationIP
val destIp = ip.sourceIP
ipHeader.setMayFragment(false)
ipHeader.sourceIP = srcIp
ipHeader.destinationIP = destIp
ipHeader.identification = PacketUtil.getPacketId()
//ip的长度是整个数据包的长度 => IP header length + UDP header length (8) + UDP body length
val totalLength = ipHeader.getIPHeaderLength() + udpLen
ipHeader.totalLength = totalLength
buffer = ByteArray(totalLength)
val ipData = ipHeader.toBytes()
// clear IP checksum
ipData[11] = 0
ipData[10] = 0
//calculate checksum for IP header
val ipChecksum = PacketUtil.calculateChecksum(ipData, 0, ipData.size)
//write result of checksum back to buffer
System.arraycopy(ipChecksum, 0, ipData, 10, 2)
System.arraycopy(ipData, 0, buffer, 0, ipData.size)
//copy UDP header to buffer
var start = ipData.size
val intContainer = ByteArray(4)
PacketUtil.writeIntToBytes(srcPort, intContainer, 0)
//extract the last two bytes of int value
System.arraycopy(intContainer, 2, buffer, start, 2)
start += 2
PacketUtil.writeIntToBytes(destPort, intContainer, 0)
System.arraycopy(intContainer, 2, buffer, start, 2)
start += 2
PacketUtil.writeIntToBytes(udpLen, intContainer, 0)
System.arraycopy(intContainer, 2, buffer, start, 2)
start += 2
val checksum: Short = 0
PacketUtil.writeIntToBytes(checksum.toInt(), intContainer, 0)
System.arraycopy(intContainer, 2, buffer, start, 2)
start += 2
//now copy udp data
if (packetData != null) System.arraycopy(packetData, 0, buffer, start, packetData.size)
return buffer
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/util/PacketUtil.kt
================================================
package com.network.proxy.vpn.util
import android.util.Log
import com.network.proxy.vpn.formatTag
import com.network.proxy.vpn.transport.protocol.IP4Header
import com.network.proxy.vpn.transport.protocol.TCPHeader
import java.nio.ByteBuffer
import java.nio.ByteOrder
/**
* Helper class to perform various useful task
*/
object PacketUtil {
@get:Synchronized
private var packetId = 0
fun getPacketId() = packetId++
val currentTime: Int
get() = (System.currentTimeMillis() / 1000).toInt()
/**
* convert int to byte array
* [...](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)
*
* @param value int value 32 bits
* @param buffer array of byte to write to
* @param offset position to write to
*/
fun writeIntToBytes(value: Int, buffer: ByteArray, offset: Int) {
if (buffer.size - offset < 4) {
return
}
buffer[offset] = (value ushr 24 and 0x000000FF).toByte()
buffer[offset + 1] = (value shr 16 and 0x000000FF).toByte()
buffer[offset + 2] = (value shr 8 and 0x000000FF).toByte()
buffer[offset + 3] = (value and 0x000000FF).toByte()
}
/**
* convert array of max 4 bytes to int
*
* @param buffer byte array
* @param start Starting point to be read in byte array
* @param length Length to be read
* @return value of int
*/
fun getNetworkInt(buffer: ByteArray, start: Int, length: Int): Int {
var value = 0
var end = start + Math.min(length, 4)
if (end > buffer.size) end = buffer.size
for (i in start until end) {
value = value or (buffer[i].toInt() and 0xFF)
if (i < end - 1) value = value shl 8
}
return value
}
/**
* validate TCP header checksum
*
* @param source Source Port
* @param destination Destination Port
* @param data Payload
* @param tcpLength TCP Header length
* @return boolean
*/
fun isValidTCPChecksum(
source: Int, destination: Int,
data: ByteArray, tcpLength: Short, tcpOffset: Int
): Boolean {
var buffersize = tcpLength + 12
var isodd = false
if (buffersize % 2 != 0) {
buffersize++
isodd = true
}
val buffer = ByteBuffer.allocate(buffersize)
buffer.putInt(source)
buffer.putInt(destination)
buffer.put(0.toByte()) //reserved => 0
buffer.put(6.toByte()) //TCP protocol => 6
buffer.putShort(tcpLength)
buffer.put(data, tcpOffset, tcpLength.toInt())
if (isodd) {
buffer.put(0.toByte())
}
return isValidIPChecksum(buffer.array(), buffersize)
}
/**
* validate IP Header checksum
*
* @param data byte stream
* @return boolean
*/
private fun isValidIPChecksum(data: ByteArray, length: Int): Boolean {
var start = 0
var sum = 0
while (start < length) {
sum += getNetworkInt(data, start, 2)
start = start + 2
}
//carry over one's complement
while (sum shr 16 > 0) sum = (sum and 0xffff) + (sum shr 16)
//flip the bit to get one' complement
sum = sum.inv()
val buffer = ByteBuffer.allocate(4)
buffer.putInt(sum)
return buffer.getShort(2).toInt() == 0
}
fun calculateChecksum(data: ByteArray, offset: Int, length: Int): ByteArray {
var start = offset
var sum = 0
while (start < length) {
sum += getNetworkInt(data, start, 2)
start = start + 2
}
//carry over one's complement
while (sum shr 16 > 0) {
sum = (sum and 0xffff) + (sum shr 16)
}
//flip the bit to get one' complement
sum = sum.inv()
//extract the last two byte of int
val checksum = ByteArray(2)
checksum[0] = (sum shr 8).toByte()
checksum[1] = sum.toByte()
return checksum
}
fun calculateTCPHeaderChecksum(
data: ByteArray,
offset: Int,
tcplength: Int,
destip: Int,
sourceip: Int
): ByteArray {
var buffersize = tcplength + 12
var odd = false
if (buffersize % 2 != 0) {
buffersize++
odd = true
}
val buffer = ByteBuffer.allocate(buffersize)
buffer.order(ByteOrder.BIG_ENDIAN)
//create virtual header
buffer.putInt(sourceip)
buffer.putInt(destip)
buffer.put(0.toByte()) //reserved => 0
buffer.put(6.toByte()) //tcp protocol => 6
buffer.putShort(tcplength.toShort())
//add actual header + data
buffer.put(data, offset, tcplength)
//padding last byte to zero
if (odd) {
buffer.put(0.toByte())
}
val tcparray = buffer.array()
return calculateChecksum(tcparray, 0, buffersize)
}
fun intToIPAddress(addressInt: Int): String {
return (addressInt ushr 24 and 0x000000FF).toString() + "." +
(addressInt ushr 16 and 0x000000FF) + "." +
(addressInt ushr 8 and 0x000000FF) + "." +
(addressInt and 0x000000FF)
}
fun getOutput(
ipHeader: IP4Header, tcpheader: TCPHeader,
packetData: ByteArray
): String {
val tcpLength = (packetData.size -
ipHeader.getIPHeaderLength()).toShort()
val isValidChecksum = isValidTCPChecksum(
ipHeader.sourceIP, ipHeader.destinationIP,
packetData, tcpLength, ipHeader.getIPHeaderLength()
)
val isValidIPChecksum = isValidIPChecksum(
packetData,
ipHeader.getIPHeaderLength()
)
val packetBodyLength = (packetData.size - ipHeader.getIPHeaderLength()
- tcpheader.getTCPHeaderLength())
val str = StringBuilder("\r\nIP Version: ")
.append(ipHeader.ipVersion.toInt())
.append("\r\nProtocol: ").append(ipHeader.protocol.toInt())
.append("\r\nID# ").append(ipHeader.identification)
.append("\r\nTotal Length: ").append(ipHeader.totalLength)
.append("\r\nData Length: ").append(packetBodyLength)
.append("\r\nDest: ").append(intToIPAddress(ipHeader.destinationIP))
.append(":").append(tcpheader.getDestinationPort())
.append("\r\nSrc: ").append(intToIPAddress(ipHeader.sourceIP))
.append(":").append(tcpheader.getSourcePort())
.append("\r\nACK: ").append(tcpheader.ackNumber)
.append("\r\nSeq: ").append(tcpheader.sequenceNumber)
.append("\r\nIP Header length: ").append(ipHeader.getIPHeaderLength())
.append("\r\nTCP Header length: ").append(tcpheader.getTCPHeaderLength())
.append("\r\nACK: ").append(tcpheader.isACK())
.append("\r\nSYN: ").append(tcpheader.isSYN())
.append("\r\nCWR: ").append(tcpheader.isCWR())
.append("\r\nECE: ").append(tcpheader.isECE())
.append("\r\nFIN: ").append(tcpheader.isFIN())
.append("\r\nNS: ").append(tcpheader.isNS)
.append("\r\nPSH: ").append(tcpheader.isPSH())
.append("\r\nRST: ").append(tcpheader.isRST())
.append("\r\nURG: ").append(tcpheader.isURG())
.append("\r\nIP checksum: ").append(ipHeader.headerChecksum)
.append("\r\nIs Valid IP Checksum: ").append(isValidIPChecksum)
.append("\r\nTCP Checksum: ").append(tcpheader.checksum)
.append("\r\nIs Valid TCP checksum: ").append(isValidChecksum)
.append("\r\nFragment Offset: ").append(ipHeader.fragmentOffset.toInt())
.append("\r\nWindow: ").append(tcpheader.windowSize)
.append("\r\nData Offset: ").append(tcpheader.dataOffset)
return str.toString()
}
/**
* detect packet corruption flag in tcp options sent from client ACK
*
* @param tcpHeader TCPHeader
* @return boolean
*/
fun isPacketCorrupted(tcpHeader: TCPHeader): Boolean {
val options = tcpHeader.options
if (options != null) {
var i = 0
while (i < options.size) {
val kind = options[i]
if (kind.toInt() == 0 || kind.toInt() == 1) {
} else if (kind.toInt() == 2) {
i += 3
} else if (kind.toInt() == 3 || kind.toInt() == 14) {
i += 2
} else if (kind.toInt() == 4) {
i++
} else if (kind.toInt() == 5 || kind.toInt() == 15) {
i = i + options[++i] - 2
} else if (kind.toInt() == 8) {
i += 9
} else if (kind.toInt() == 23) {
return true
} else {
Log.e(
formatTag(PacketUtil::class.java.name),
"unknown option: $kind"
)
}
i++
}
}
return false
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/util/ProcessInfoManager.kt
================================================
package com.network.proxy.vpn.util
import android.content.Context
import android.net.ConnectivityManager
import android.os.Build
import android.os.Process
import android.system.OsConstants
import android.util.Log
import androidx.annotation.RequiresApi
import com.network.proxy.ProxyVpnService
import com.network.proxy.plugin.ProcessInfo
import com.network.proxy.vpn.Connection
import kotlinx.coroutines.CoroutineScope
import java.io.File
import java.net.InetSocketAddress
import java.nio.channels.SocketChannel
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* 进程信息管理器,用于获取进程信息
* @author wanghongen
*/
class ProcessInfoManager private constructor() {
companion object {
@Suppress("all")
val instance = ProcessInfoManager()
}
class NetworkInfo(val uid: Int, val remoteHost: String, val remotePort: Int)
private val localPortCache =
SimpleCache<Int, NetworkInfo>(10_000, 60, TimeUnit.SECONDS)
private val appInfoCache = SimpleCache<Int, ProcessInfo>(10_000, 300, TimeUnit.SECONDS)
var activity: Context? = null
@RequiresApi(Build.VERSION_CODES.N)
fun setConnectionOwnerUid(connection: Connection) {
CoroutineScope(Dispatchers.IO).launch {
val sourceAddress =
InetSocketAddress(PacketUtil.intToIPAddress(connection.sourceIp), connection.sourcePort)
val destinationAddress = InetSocketAddress(
PacketUtil.intToIPAddress(connection.destinationIp), connection.destinationPort
)
val uid = getProcessInfoUid(sourceAddress, destinationAddress)
val channel = connection.channel
if (uid != null && uid != Process.INVALID_UID && channel is SocketChannel && channel.isOpen) {
try {
val localAddress = channel.localAddress as InetSocketAddress
val networkInfo =
NetworkInfo(uid, destinationAddress.hostString, destinationAddress.port)
localPortCache.put(localAddress.port, networkInfo)
} catch (e: java.nio.channels.ClosedChannelException) {
Log.w("ProcessInfoManager", "setConnectionOwnerUid", e)
}
}
}
}
fun removeConnection(connection: Connection) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
return
}
val channel = connection.channel
if (channel is SocketChannel && channel.isOpen) {
try {
val localAddress = channel.localAddress as InetSocketAddress
localPortCache.remove(localAddress.port)
} catch (e: java.nio.channels.ClosedChannelException) {
Log.w("ProcessInfoManager", "removeConnection", e)
}
}
}
@RequiresApi(Build.VERSION_CODES.N)
private fun getProcessInfoUid(
localAddress: InetSocketAddress, remoteAddress: InetSocketAddress
): Int? {
// Log.d(TAG, "getProcessInfo: $localAddress $remoteAddress")
if (activity == null) {
return null
}
try {
val connectivityManager: ConnectivityManager =
activity!!.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val uid = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
connectivityManager.getConnectionOwnerUid(
OsConstants.IPPROTO_TCP, localAddress, remoteAddress
)
} else {
val method = ConnectivityManager::class.java.getMethod(
"getConnectionOwnerUid",
Int::class.javaPrimitiveType,
InetSocketAddress::class.java,
InetSocketAddress::class.java
)
method.invoke(
connectivityManager, OsConstants.IPPROTO_TCP, localAddress, remoteAddress
) as Int
}
if (uid != Process.INVALID_UID) {
return uid
}
} catch (e: Exception) {
Log.w("ProcessInfoManager", "Exception in getProcessInfoUid", e)
return null
}
Log.w(
"ProcessInfoManager",
"Failed to get UID for local address $localAddress and remote address $remoteAddress"
)
return null
}
suspend fun getProcessInfoByPort(host: String?, localPort: Int): ProcessInfo? {
val networkInfo = localPortCache.get(localPort)
if (networkInfo != null) {
val processInfo = getProcessInfo(networkInfo.uid)
if (processInfo != null) {
val result = processInfo.copy()
result["remoteHost"] = networkInfo.remoteHost
result["remotePort"] = networkInfo.remotePort
return result
}
return null
}
if (host == null || localPort <= 0 || ProxyVpnService.host == null || ProxyVpnService.port <= 0) {
Log.w("ProcessInfoManager", "Invalid host or local port: $host:$localPort or ProxyVpnService not initialized")
return null
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return withContext(Dispatchers.IO) {
val localAddress = InetSocketAddress(host, localPort)
val remoteAddress = InetSocketAddress(ProxyVpnService.host, ProxyVpnService.port)
val uid = getProcessInfoUid(localAddress, remoteAddress)
if (uid == null || uid == Process.INVALID_UID) {
return@withContext null
}
val processInfo = getProcessInfo(uid)
if (processInfo != null) {
localPortCache.put(
localPort, NetworkInfo(uid, remoteAddress.hostString, remoteAddress.port)
)
val result = processInfo.copy()
result["remoteHost"] = remoteAddress.hostString
result["remotePort"] = remoteAddress.port
return@withContext result
} else {
Log.w("ProcessInfoManager", "No process info found for UID: $uid")
null
}
}
} else {
Log.w("ProcessInfoManager", "Access to /proc/net/tcp is restricted on non-rooted devices.")
}
return null
}
fun getRemoteAddressByPort(localPort: Int): Map<String, Any>? {
val networkInfo = localPortCache.get(localPort)
if (networkInfo != null) {
return mapOf(
"remoteHost" to networkInfo.remoteHost,
"remotePort" to networkInfo.remotePort
)
}
return null
}
private fun getProcessInfo(uid: Int): ProcessInfo? {
var appInfo = appInfoCache.get(uid)
if (appInfo != null) return appInfo
val packageManager = activity?.packageManager ?: return null
val pkgNames: Array<String>? = try {
packageManager.getPackagesForUid(uid)
} catch (e: Exception) {
Log.w("ProcessInfoManager", "getPackagesForUid SecurityException: $uid", e)
null
}
if (pkgNames == null) return null
for (pkgName in pkgNames) {
try {
val applicationInfo = packageManager.getApplicationInfo(pkgName, 0)
appInfo = ProcessInfo.create(packageManager, applicationInfo)
appInfoCache.put(uid, appInfo)
return appInfo
} catch (e: Exception) {
// Ignore packages that can't be found
}
}
return null
}
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/util/SimpleCache.kt
================================================
package com.network.proxy.vpn.util
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
class SimpleCache<K, V>(
private val maxSize: Int,
private val expireAfterAccess: Long,
private val timeUnit: TimeUnit
) {
private val cache = ConcurrentHashMap<K, CacheEntry<V>>()
companion object {
private val EXECUTOR = Executors.newSingleThreadScheduledExecutor()
}
init {
EXECUTOR.scheduleWithFixedDelay(
{ cleanUp() },
expireAfterAccess,
expireAfterAccess,
timeUnit
)
}
fun put(key: K, value: V) {
if (cache.size >= maxSize) {
cache.keys.iterator().next()?.let { cache.remove(it) }
}
cache[key] = CacheEntry(value, System.nanoTime())
}
fun get(key: K): V? {
val entry = cache[key] ?: return null
if (System.nanoTime() - entry.lastAccessTime > timeUnit.toNanos(expireAfterAccess)) {
cache.remove(key)
return null
}
entry.lastAccessTime = System.nanoTime()
return entry.value
}
fun remove(key: K) {
cache.remove(key)
}
fun clear() {
cache.clear()
}
private fun cleanUp() {
val now = System.nanoTime()
val expirationTime = timeUnit.toNanos(expireAfterAccess)
val iterator = cache.entries.iterator()
while (iterator.hasNext()) {
val entry = iterator.next()
if (now - entry.value.lastAccessTime > expirationTime) {
iterator.remove()
}
}
}
private data class CacheEntry<V>(val value: V, var lastAccessTime: Long)
}
================================================
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/util/TLS.kt
================================================
package com.network.proxy.vpn.util
import java.nio.ByteBuffer
import kotlin.math.min
object TLS {
/**
* 判断是否是TLS Client Hello
*/
fun isTLSClientHello(packetData: ByteBuffer): Boolean {
if (packetData.remaining() < 43) return false
val position = packetData.position()
val data = packetData.array()
if (data[position].toInt() != 0x16 /* handshake */) return false
if (data[1 + position].toInt() != 0x03) return false
return if (data[5 + position].toInt() != 0x01) false else data[9 + position].toInt() == 0x03 && data[10 + position] >= 0x00 && data[1 + position] <= 0x03
}
/**
* 从TLS Client Hello 解析域名
*/
fun getDomain(buffer: ByteBuffer): String? {
var offset = buffer.position()
val limit = buffer.limit()
//TLS Client Hello
if (buffer[offset].toInt() != 0x16) return null
//Skip 43 byte header
offset += 43
if (limit < (offset + 1)) return null
//read session id
val sessionIDLength = buffer[offset++]
offset += sessionIDLength
//read cipher suites
if (offset + 2 > limit) return null
val cipherSuitesLength = buffer.getShort(offset)
offset += 2
offset += cipherSuitesLength
//read Compression method.
if (offset + 1 > limit) return null
val compressionMethodLength = buffer[offset++].toInt() and 0xFF
offset += compressionMethodLength
if (offset > limit) return null
//read Extensions
if (offset + 2 > limit) return null
val extensionsLength = buffer.getShort(offset)
offset += 2
if (offset + extensionsLength > limit) return null
var end: Int = offset + extensionsLength
end = min(end, limit)
while (offset + 4 <= end) {
val extensionType = buffer.getShort(offset)
val extensionLength = buffer.getShort(offset + 2)
offset += 4
//server_name
if (extensionType.toInt() == 0) {
if (offset + 5 > limit) return null
val serverNameListLength = buffer.getShort(offset)
offset += 2
if (offset > limit) return null
if (offset + serverNameListLength > limit) return null
val serverNameType = buffer[offset++]
val serverNameLength = buffer.getShort(offset)
offset += 2
if (offset > limit || serverNameType.toInt() != 0) return null
if (offset + serverNameLength > limit) return null
val serverNameBytes = ByteArray(serverNameLength.toInt())
buffer.get(serverNameBytes)
return String(serverNameBytes)
} else {
offset += extensionLength
}
}
return null
}
}
================================================
FILE: android/app/src/main/res/drawable/launch_background.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
================================================
FILE: android/app/src/main/res/drawable-v21/launch_background.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
================================================
FILE: android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
</adaptive-icon>
================================================
FILE: android/app/src/main/res/values/styles.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
<string name="vpn_active_notification_title">ProxyPin Active</string>
<string name="vpn_active_notification_content">抓包正在运行</string>
</resources>
================================================
FILE: android/app/src/main/res/values-night/styles.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
================================================
FILE: android/app/src/profile/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
================================================
FILE: android/build.gradle
================================================
allprojects {
repositories {
google()
mavenCentral()
}
subprojects {
afterEvaluate { project ->
if (project.hasProperty('android')) {
project.android {
if (namespace == null) {
namespace project.group
}
}
}
}
}
}
rootProject.buildDir = '../build'
subprojects {
afterEvaluate { project ->
if (project.extensions.findByName("android") != null) {
Integer pluginCompileSdk = project.android.compileSdk
if (pluginCompileSdk != null && pluginCompileSdk < 31) {
project.logger.error(
"Warning: Overriding compileSdk version in Flutter plugin: "
+ project.name
+ " from "
+ pluginCompileSdk
+ " to 31 (to work around https://issuetracker.google.com/issues/199180389)."
+ "\nIf there is not a new version of " + project.name + ", consider filing an issue against "
+ project.name
+ " to increase their compileSdk to the latest (otherwise try updating to the latest version)."
)
project.android {
compileSdk 31
}
}
}
}
}
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
================================================
FILE: android/gradle/wrapper/gradle-wrapper.properties
================================================
#Tue Nov 28 00:35:45 CST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
================================================
FILE: android/gradle.properties
================================================
org.gradle.jvmargs=-Xmx4G
android.useAndroidX=true
android.enableJetifier=true
android.nonFinalResIds=false
================================================
FILE: android/settings.gradle
================================================
import java.util.Properties
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}
settings.ext.flutterSdkPath = flutterSdkPath()
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version '8.9.1' apply false
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
}
include ":app"
================================================
FILE: assets/certs/ca.crt
================================================
-----BEGIN CERTIFICATE-----
MIID4jCCAsqgAwIBAgIJAKcH8Dna4mnZMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV
BAYTAkNOMQswCQYDVQQIDAJCSjEQMA4GA1UEBwwHQmVpSmluZzERMA8GA1UECgwI
UHJveHlQaW4xETAPBgNVBAsMCFByb3h5UGluMRQwEgYDVQQDDAtQcm94eVBpbiBD
QTAeFw0yMzA2MjQxNjA2MDlaFw0zMzA2MjExNjA2MTBaMGgxCzAJBgNVBAYTAkNO
MQswCQYDVQQIDAJCSjEQMA4GA1UEBwwHQmVpSmluZzERMA8GA1UECgwIUHJveHlQ
aW4xETAPBgNVBAsMCFByb3h5UGluMRQwEgYDVQQDDAtQcm94eVBpbiBDQTCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRjfFvFDZS+PsdedUNq0Kn5t7RF
NS0iQrZALr4LJm3UwtatHtMEWBb9ptam8pWezxrZPZ81+qnTcaq/To82yus5hJa4
JRk223YWn5JDd4izH4gcnSomhUQ6Ycrc0v+I7UEaHV+bQsleHEfYi2+E1qF+FBhR
veLSPmz2QORd/U4+gDlOptgNWMQ9OTRHsMoDzb8J4SlcBu+s0dnq2WHOM9boGnfk
2wIgE+16uB23epPoYjex8zYGUswh8gNrIzXsr7i9IGtGf67FQYCWOXfZLeGgy0Q0
/r1lwSmywUkNaZIsiGZHveZsLtW93MWMFw0uneEvHsuQV+e8sdLI/633TGcCAwEA
AaOBjjCBizAdBgNVHQ4EFgQU4YXwKkBDFoZY3D81RM25ECSc2qcwHwYDVR0jBBgw
FoAU4YXwKkBDFoZY3D81RM25ECSc2qcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
Af8EBAMCAaYwEwYDVR0RBAwwCoIIUHJveHlQaW4wEwYDVR0lBAwwCgYIKwYBBQUH
AwEwDQYJKoZIhvcNAQELBQADggEBAAc2s5TwuOdPdl3gYs121sY+HEMyXfsnVTGV
dIlgjf+a0ECir2bcs64udaCIgBjd/vqhShMeqeQ4GJW7Ypb9556L213xjbLj/ZVU
rgZda6oVd4der8YEHXKLxWAGlZQeeKHhw1lN4PYwxxGaf7/wsM7Dil0JLyOBtJaJ
zNRzVzK9UHASDx0qDQVUBbeYzRviVCjxAGBNM/eNlPDX7m//vgCLxQgcxVdoJvMQ
kSVQddo+d8fxnPAVx77dyX0T/ek7PQOsL6d08TVCdvgv50LwE8f9EMhHVv7zjEv2
0ZSaRQ0pvUnc0ClKXIGeMD71eYeeTz7CGjndxy5bdV/wmoo3Yek=
-----END CERTIFICATE-----
================================================
FILE: assets/certs/ca_key.pem
================================================
-----BEGIN CERTIFICATE-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDEY3xbxQ2Uvj7H
XnVDatCp+be0RTUtIkK2QC6+CyZt1MLWrR7TBFgW/abWpvKVns8a2T2fNfqp03Gq
v06PNsrrOYSWuCUZNtt2Fp+SQ3eIsx+IHJ0qJoVEOmHK3NL/iO1BGh1fm0LJXhxH
2ItvhNahfhQYUb3i0j5s9kDkXf1OPoA5TqbYDVjEPTk0R7DKA82/CeEpXAbvrNHZ
6tlhzjPW6Bp35NsCIBPtergdt3qT6GI3sfM2BlLMIfIDayM17K+4vSBrRn+uxUGA
ljl32S3hoMtENP69ZcEpssFJDWmSLIhmR73mbC7VvdzFjBcNLp3hLx7LkFfnvLHS
yP+t90xnAgMBAAECggEAPYnPFhKRRuK2WVLH+/Akop6Vae+l0hbCQMmr2/EygYgB
5bMpzYW29L1W4jw+F5RD4W3hWVpYyY5wN8jqnQXWYA8N9QyO02/VJRPBvNtXQYaf
gs80kFixucdxjVfU5i3J6nR8b9D/BIpw4jKAvtkpSEFxmo1CqyimVw5zFxw8m599
gJX/WeA88l9/4/tGQ24TAZV7OaP+jgqb4hOPC6gB5YHYnGFfuAh8q1Gf3wGnU+3/
pdEDq1UPvMwZ3J7ifTjMHYh2gnT/xQSxOddbtNJfaBx8fUFC4GVEEZ1+j0zc2bOp
/7q+Ab0QXLjMbe3bftMZZqffp2X6NLJipLQcw/HRQQKBgQDonHdqt5ZcsF7+Vsl4
KwmMNAz+jO6j51LU60F7QDhk7hGkCvUF2zJgYSkjlUNl6VS5aGmWTyUR3T3Eqiqs
r81Qao5mxF0MjUU2QKgsw57YG2yASgSPdGqW0PFu1yrxLS51qLIGbp5AuZLULO+M
iTvO1SRm29q45F9f/m0NRda0TQKBgQDYIqGVFcyQvQzGPZc5iOI9we526p+MGEsa
ysRHs8wXJKCiINH2iw1bJGyRCOIZyFQwMRteC174tRnyZpsgTu6wTgaVnTHS8ZNQ
LfjAQsMbs7TItjQF88/thujP15BXzTN7HN1y5kOVCAI7EvLJlZ4jMewfj+aqv2Sb
o5ungsWtgwKBgQCgo2WIqk5JpneDt9WcikQmsc+DfzpSsK6wYeMvxbLsaMh//B0o
NS8+BftOGoeX+qJLBINejTuxcZN1nHqqFSJ59YxwBg2oXGs+wzog59trrMyqb/Nk
SmZNzu/ctvVt5uDd2mlPLddWJZHzuzCXYjKObP2dlxkedIA1H9SZxPA4RQKBgDAS
29/ePmb/NcUuU+GfObtE1HaszxoJGUN3UFsmecG4Cuak6C6vVSQtoNxNnoTfkyI4
+f5cBx7IoWHSQrTX+a1LXZmPolJqGzsdTpPtBZq2yQJPzJh6V4hclpIMP3XYFZhP
nk39O5D9fAmJuGjwF4F6jCulBUh7U7RumqOSqcdjAoGBAKxCtQ0XT0Rlc6B37xTK
/fVYaVbSDISBSVYJTy5vjQi5z+bqUaQrmfeW1z+WoVTeP0ZUgcxTXJbPBVeAC8Wx
oTYfh5yTEu8FCBpBSWWsCteodBBZxXpINLuk9Ex44yxvuFhulugmYzyga+nqufV/
N5e8NEl7aISBW+PK16pnNO0e
-----END CERTIFICATE-----
================================================
FILE: assets/js/fetch.js
================================================
function fetch(url, options) {
options = options || {};
return new Promise((resolve, reject) => {
const request = new XMLHttpRequest();
const keys = [];
const all = [];
const headers = {};
const response = () => ({
ok: (request.status / 100 | 0) === 2, // 200-299
statusText: request.statusText,
status: request.status,
url: request.responseURL,
body: request.response.body,
text: () => Promise.resolve(request.responseText),
json: () => {
// TODO: review this handle because it may discard \n from json attributes
try {
// console.log('RESPONSE TEXT IN FETCH: ' + request.responseText);
return Promise.resolve(JSON.parse(request.responseText));
} catch (e) {
// console.log('ERROR on fetch parsing JSON: ' + e.message);
return Promise.resolve(request.responseText);
}
},
blob: () => Promise.resolve(request.response.body),
clone: response,
headers: {
...headers,
keys: () => keys,
entries: () => all,
get: n => headers[n.toLowerCase()],
has: n => n.toLowerCase() in headers,
}
});
request.open(options.method || 'get', url, true);
request.onload = () => {
request.getAllResponseHeaders().replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm, (m, key, value) => {
keys.push(key = key.toLowerCase());
all.push([key, value]);
headers[key] = headers[key] ? `${headers[key]},${value}` : value;
});
resolve(response());
};
request.onerror = reject;
request.withCredentials = options.credentials == 'include';
if (options.headers) {
if (options.headers.constructor.name == 'Object') {
for (const i in options.headers) {
request.setRequestHeader(i, options.headers[i]);
}
} else { // if it is some Headers pollyfill, the way to iterate is through for of
for (const header of options.headers) {
request.setRequestHeader(header[0], header[1]);
}
}
}
request.send(options.body || null);
});
}
================================================
FILE: devtools_options.yaml
================================================
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
================================================
FILE: distribute_options.yaml
================================================
output: dist/
releases:
- name: release
jobs:
- name: macos-dmg
package:
platform: macos
target: dmg
build_args:
profile: true
- name: windows-exe
package:
platform: windows
target: exe
build_args:
profile: true
- name: windows-msix
package:
platform: windows
target: msix
- name: windows-zip
package:
platform: windows
target: zip
================================================
FILE: ios/.gitignore
================================================
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
================================================
FILE: ios/Flutter/AppFrameworkInfo.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>13.0</string>
</dict>
</plist>
================================================
FILE: ios/Flutter/Debug.xcconfig
================================================
#include? "Pods/Target Support Files/Pod
gitextract_xlm06j4i/
├── .github/
│ └── ISSUE_TEMPLATE/
│ ├── bug_report.yml
│ ├── feature_request.yml
│ └── 功能请求.yml
├── .gitignore
├── .metadata
├── LICENSE
├── README.md
├── README_CN.md
├── analysis_options.yaml
├── android/
│ ├── .gitignore
│ ├── app/
│ │ ├── build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ ├── debug/
│ │ │ └── AndroidManifest.xml
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin/
│ │ │ │ └── com/
│ │ │ │ └── network/
│ │ │ │ └── proxy/
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── ProxyVpnService.kt
│ │ │ │ ├── VpnAlertDialog.kt
│ │ │ │ ├── plugin/
│ │ │ │ │ ├── AndroidFlutterPlugin.kt
│ │ │ │ │ ├── AppInfo.kt
│ │ │ │ │ ├── AppLifecyclePlugin.kt
│ │ │ │ │ ├── InstalledAppsPlugin.kt
│ │ │ │ │ ├── PictureInPicturePlugin.kt
│ │ │ │ │ ├── ProcessInfoPlugin.kt
│ │ │ │ │ └── VpnServicePlugin.kt
│ │ │ │ └── vpn/
│ │ │ │ ├── Connection.kt
│ │ │ │ ├── ConnectionHandler.kt
│ │ │ │ ├── ConnectionManager.kt
│ │ │ │ ├── Protocol.java
│ │ │ │ ├── ProxyVpnThread.kt
│ │ │ │ ├── Tag.kt
│ │ │ │ ├── socket/
│ │ │ │ │ ├── ClientPacketWriter.kt
│ │ │ │ │ ├── CloseableConnection.kt
│ │ │ │ │ ├── Constant.kt
│ │ │ │ │ ├── ProtectSocket.kt
│ │ │ │ │ ├── ProtectSocketHolder.kt
│ │ │ │ │ ├── SocketChannelReader.java
│ │ │ │ │ ├── SocketChannelWriter.java
│ │ │ │ │ └── SocketNIODataService.java
│ │ │ │ ├── transport/
│ │ │ │ │ ├── Packet.kt
│ │ │ │ │ ├── icmp/
│ │ │ │ │ │ ├── ICMPPacket.java
│ │ │ │ │ │ └── ICMPPacketFactory.java
│ │ │ │ │ └── protocol/
│ │ │ │ │ ├── IP4Header.kt
│ │ │ │ │ ├── TCPHeader.kt
│ │ │ │ │ ├── TCPPacketFactory.kt
│ │ │ │ │ ├── TransportHeader.kt
│ │ │ │ │ └── UDPHeader.kt
│ │ │ │ └── util/
│ │ │ │ ├── PacketUtil.kt
│ │ │ │ ├── ProcessInfoManager.kt
│ │ │ │ ├── SimpleCache.kt
│ │ │ │ └── TLS.kt
│ │ │ └── res/
│ │ │ ├── drawable/
│ │ │ │ └── launch_background.xml
│ │ │ ├── drawable-v21/
│ │ │ │ └── launch_background.xml
│ │ │ ├── mipmap-anydpi-v26/
│ │ │ │ └── ic_launcher.xml
│ │ │ ├── values/
│ │ │ │ └── styles.xml
│ │ │ └── values-night/
│ │ │ └── styles.xml
│ │ └── profile/
│ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ └── settings.gradle
├── assets/
│ ├── certs/
│ │ ├── ca.crt
│ │ ├── ca_key.pem
│ │ └── ca_private.der
│ └── js/
│ └── fetch.js
├── devtools_options.yaml
├── distribute_options.yaml
├── ios/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Podfile
│ ├── ProxyPin/
│ │ ├── Info.plist
│ │ ├── PacketTunnelProvider.swift
│ │ ├── ProxyPin-Bridging-Header.h
│ │ ├── ProxyPin.entitlements
│ │ └── vpn/
│ │ ├── Connection.swift
│ │ ├── ConnectionHandler.swift
│ │ ├── ConnectionManager.swift
│ │ ├── NWProtocol.swift
│ │ ├── ProxyVpnService.swift
│ │ ├── QueueFactory.swift
│ │ ├── ping/
│ │ │ ├── GBPing.h
│ │ │ ├── GBPing.m
│ │ │ ├── GBPingHelper.swift
│ │ │ ├── GBPingSummary.h
│ │ │ ├── GBPingSummary.m
│ │ │ └── ICMPHeader.h
│ │ ├── socket/
│ │ │ ├── ClientPacketWriter.swift
│ │ │ ├── CloseableConnection.swift
│ │ │ └── SocketIOService.swift
│ │ ├── transport/
│ │ │ ├── Packet.swift
│ │ │ └── protocol/
│ │ │ ├── ICMPPacket.swift
│ │ │ ├── IP4Header.swift
│ │ │ ├── TCPHeader.swift
│ │ │ ├── TCPPacketFactory.swift
│ │ │ ├── TransportHeader.swift
│ │ │ └── UDPHeader.swift
│ │ └── utils/
│ │ ├── PacketUtil.swift
│ │ └── TLS.swift
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── LaunchImage.imageset/
│ │ │ ├── Contents.json
│ │ │ └── README.md
│ │ ├── AudioManager.swift
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Handlers/
│ │ │ └── MethodHandler.swift
│ │ ├── Info.plist
│ │ ├── Runner-Bridging-Header.h
│ │ ├── Runner.entitlements
│ │ ├── VpnManager.swift
│ │ ├── en.lproj/
│ │ │ └── InfoPlist.strings
│ │ ├── pip/
│ │ │ ├── PictureInPictureManager.swift
│ │ │ └── PictureInPictureView.swift
│ │ └── zh-Hans.lproj/
│ │ ├── InfoPlist.strings
│ │ ├── LaunchScreen.strings
│ │ └── Main.strings
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
│ └── RunnerTests/
│ └── RunnerTests.swift
├── l10n.yaml
├── lib/
│ ├── l10n/
│ │ ├── app_en.arb
│ │ ├── app_localizations.dart
│ │ ├── app_localizations_en.dart
│ │ ├── app_localizations_zh.dart
│ │ ├── app_zh.arb
│ │ └── app_zh_Hant.arb
│ ├── main.dart
│ ├── native/
│ │ ├── app_lifecycle.dart
│ │ ├── installed_apps.dart
│ │ ├── native_method.dart
│ │ ├── pip.dart
│ │ ├── process_info.dart
│ │ └── vpn.dart
│ ├── network/
│ │ ├── bin/
│ │ │ ├── configuration.dart
│ │ │ ├── listener.dart
│ │ │ └── server.dart
│ │ ├── channel/
│ │ │ ├── channel.dart
│ │ │ ├── channel_context.dart
│ │ │ ├── channel_dispatcher.dart
│ │ │ ├── host_port.dart
│ │ │ └── network.dart
│ │ ├── components/
│ │ │ ├── host_filter.dart
│ │ │ ├── hosts.dart
│ │ │ ├── interceptor.dart
│ │ │ ├── js/
│ │ │ │ ├── file.dart
│ │ │ │ ├── md5.dart
│ │ │ │ ├── script_engine.dart
│ │ │ │ └── xhr.dart
│ │ │ ├── manager/
│ │ │ │ ├── hosts_manager.dart
│ │ │ │ ├── report_server_manager.dart
│ │ │ │ ├── request_block_manager.dart
│ │ │ │ ├── request_breakpoint_manager.dart
│ │ │ │ ├── request_crypto_manager.dart
│ │ │ │ ├── request_map_manager.dart
│ │ │ │ ├── request_rewrite_manager.dart
│ │ │ │ ├── rewrite_rule.dart
│ │ │ │ └── script_manager.dart
│ │ │ ├── report_server_interceptor.dart
│ │ │ ├── request_block.dart
│ │ │ ├── request_breakpoint.dart
│ │ │ ├── request_map.dart
│ │ │ ├── request_rewrite.dart
│ │ │ └── script.dart
│ │ ├── handle/
│ │ │ ├── http_proxy_handle.dart
│ │ │ ├── relay_handle.dart
│ │ │ ├── sse_handle.dart
│ │ │ └── websocket_handle.dart
│ │ ├── http/
│ │ │ ├── codec.dart
│ │ │ ├── constants.dart
│ │ │ ├── content_type.dart
│ │ │ ├── h2/
│ │ │ │ ├── frame.dart
│ │ │ │ ├── h2_codec.dart
│ │ │ │ ├── hpack/
│ │ │ │ │ ├── hpack.dart
│ │ │ │ │ ├── huffman.dart
│ │ │ │ │ └── huffman_table.dart
│ │ │ │ └── setting.dart
│ │ │ ├── http.dart
│ │ │ ├── http_client.dart
│ │ │ ├── http_headers.dart
│ │ │ ├── parse/
│ │ │ │ ├── body_reader.dart
│ │ │ │ └── http_parser.dart
│ │ │ ├── sse.dart
│ │ │ └── websocket.dart
│ │ ├── socks/
│ │ │ └── socks5.dart
│ │ └── util/
│ │ ├── attribute_keys.dart
│ │ ├── byte_buf.dart
│ │ ├── byte_utils.dart
│ │ ├── cache.dart
│ │ ├── cert/
│ │ │ ├── basic_constraints.dart
│ │ │ ├── cert_data.dart
│ │ │ ├── der.dart
│ │ │ ├── extension.dart
│ │ │ ├── key_usage.dart
│ │ │ ├── pkcs12.dart
│ │ │ └── x509.dart
│ │ ├── compress.dart
│ │ ├── crts.dart
│ │ ├── crypto.dart
│ │ ├── file_read.dart
│ │ ├── lang.dart
│ │ ├── localizations.dart
│ │ ├── logger.dart
│ │ ├── process_info.dart
│ │ ├── proxy_helper.dart
│ │ ├── random.dart
│ │ ├── socket_address.dart
│ │ ├── system_proxy.dart
│ │ ├── task_queue.dart
│ │ ├── tls.dart
│ │ └── uri.dart
│ ├── storage/
│ │ ├── favorites.dart
│ │ ├── histories.dart
│ │ ├── local_storage.dart
│ │ ├── path.dart
│ │ └── shared_preference_keys.dart
│ ├── ui/
│ │ ├── app_update/
│ │ │ ├── app_update_repository.dart
│ │ │ ├── constants.dart
│ │ │ ├── new_version_dialog.dart
│ │ │ └── remote_version_entity.dart
│ │ ├── component/
│ │ │ ├── app_dialog.dart
│ │ │ ├── buttons.dart
│ │ │ ├── chinese_font.dart
│ │ │ ├── context_menu_region.dart
│ │ │ ├── device.dart
│ │ │ ├── history_cache_time.dart
│ │ │ ├── http_method_popup.dart
│ │ │ ├── json/
│ │ │ │ ├── json_text.dart
│ │ │ │ ├── json_viewer.dart
│ │ │ │ ├── theme.dart
│ │ │ │ └── toast.dart
│ │ │ ├── memory_cleanup.dart
│ │ │ ├── model/
│ │ │ │ └── search_model.dart
│ │ │ ├── multi_window.dart
│ │ │ ├── proxy_port_setting.dart
│ │ │ ├── qrcode/
│ │ │ │ └── qr_scan_view.dart
│ │ │ ├── search/
│ │ │ │ ├── highlight_text.dart
│ │ │ │ ├── search_controller.dart
│ │ │ │ └── search_field.dart
│ │ │ ├── search_condition.dart
│ │ │ ├── split_view.dart
│ │ │ ├── state_component.dart
│ │ │ ├── text_field.dart
│ │ │ ├── transition.dart
│ │ │ ├── utils.dart
│ │ │ └── widgets.dart
│ │ ├── configuration.dart
│ │ ├── content/
│ │ │ ├── body.dart
│ │ │ ├── headers.dart
│ │ │ ├── menu.dart
│ │ │ ├── panel.dart
│ │ │ └── web_socket.dart
│ │ ├── desktop/
│ │ │ ├── common.dart
│ │ │ ├── debug/
│ │ │ │ └── breakpoint_executor.dart
│ │ │ ├── desktop.dart
│ │ │ ├── left_menus/
│ │ │ │ ├── favorite.dart
│ │ │ │ ├── history.dart
│ │ │ │ └── navigation.dart
│ │ │ ├── preference.dart
│ │ │ ├── request/
│ │ │ │ ├── domians.dart
│ │ │ │ ├── list.dart
│ │ │ │ ├── repeat.dart
│ │ │ │ ├── report_servers.dart
│ │ │ │ ├── request.dart
│ │ │ │ ├── request_editor.dart
│ │ │ │ ├── request_sequence.dart
│ │ │ │ └── search.dart
│ │ │ ├── setting/
│ │ │ │ ├── about.dart
│ │ │ │ ├── external_proxy.dart
│ │ │ │ ├── filter.dart
│ │ │ │ ├── hosts.dart
│ │ │ │ ├── request_block.dart
│ │ │ │ ├── request_breakpoint.dart
│ │ │ │ ├── request_crypto.dart
│ │ │ │ ├── request_map/
│ │ │ │ │ ├── map_local.dart
│ │ │ │ │ └── map_scipt.dart
│ │ │ │ ├── request_map.dart
│ │ │ │ ├── request_rewrite.dart
│ │ │ │ ├── rewrite/
│ │ │ │ │ ├── rewrite_replace.dart
│ │ │ │ │ └── rewrite_update.dart
│ │ │ │ ├── script.dart
│ │ │ │ └── setting.dart
│ │ │ ├── ssl/
│ │ │ │ ├── cert_installer.dart
│ │ │ │ ├── pc_cert.dart
│ │ │ │ └── ssl.dart
│ │ │ ├── toolbar/
│ │ │ │ ├── phone_connect.dart
│ │ │ │ └── toolbar.dart
│ │ │ ├── widgets/
│ │ │ │ ├── highlight.dart
│ │ │ │ └── windows_toolbar.dart
│ │ │ └── window_listener.dart
│ │ ├── launch/
│ │ │ └── launch.dart
│ │ ├── mobile/
│ │ │ ├── debug/
│ │ │ │ └── breakpoint_executor.dart
│ │ │ ├── menu/
│ │ │ │ ├── bottom_navigation.dart
│ │ │ │ ├── drawer.dart
│ │ │ │ └── menu.dart
│ │ │ ├── mobile.dart
│ │ │ ├── request/
│ │ │ │ ├── domians.dart
│ │ │ │ ├── favorite.dart
│ │ │ │ ├── history.dart
│ │ │ │ ├── list.dart
│ │ │ │ ├── repeat.dart
│ │ │ │ ├── request.dart
│ │ │ │ ├── request_editor.dart
│ │ │ │ ├── request_editor_source.dart
│ │ │ │ ├── request_sequence.dart
│ │ │ │ └── search.dart
│ │ │ ├── setting/
│ │ │ │ ├── app_filter.dart
│ │ │ │ ├── filter.dart
│ │ │ │ ├── hosts.dart
│ │ │ │ ├── preference.dart
│ │ │ │ ├── proxy.dart
│ │ │ │ ├── report_servers.dart
│ │ │ │ ├── request_block.dart
│ │ │ │ ├── request_breakpoint.dart
│ │ │ │ ├── request_crypto.dart
│ │ │ │ ├── request_map/
│ │ │ │ │ ├── map_local.dart
│ │ │ │ │ └── map_scipt.dart
│ │ │ │ ├── request_map.dart
│ │ │ │ ├── request_rewrite.dart
│ │ │ │ ├── rewrite/
│ │ │ │ │ ├── rewrite_replace.dart
│ │ │ │ │ └── rewrite_update.dart
│ │ │ │ ├── script.dart
│ │ │ │ ├── ssl.dart
│ │ │ │ ├── theme.dart
│ │ │ │ └── video_player.dart
│ │ │ └── widgets/
│ │ │ ├── about.dart
│ │ │ ├── floating_window.dart
│ │ │ ├── highlight.dart
│ │ │ ├── pip.dart
│ │ │ └── remote_device.dart
│ │ └── toolbox/
│ │ ├── aes_page.dart
│ │ ├── cert_hash.dart
│ │ ├── encoder.dart
│ │ ├── js_run.dart
│ │ ├── qr_code_page.dart
│ │ ├── regexp.dart
│ │ ├── timestamp.dart
│ │ ├── toolbox.dart
│ │ └── websocket_request.dart
│ └── utils/
│ ├── aes.dart
│ ├── crypto_body_decoder.dart
│ ├── curl.dart
│ ├── desktop_support.dart
│ ├── export_request.dart
│ ├── files.dart
│ ├── font.dart
│ ├── har.dart
│ ├── ip.dart
│ ├── keyword_highlight.dart
│ ├── lang.dart
│ ├── listenable_list.dart
│ ├── navigator.dart
│ ├── num.dart
│ ├── platform.dart
│ ├── python.dart
│ └── task.dart
├── linux/
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── build.sh
│ ├── flutter/
│ │ ├── CMakeLists.txt
│ │ ├── generated_plugin_registrant.cc
│ │ ├── generated_plugin_registrant.h
│ │ └── generated_plugins.cmake
│ ├── main.cc
│ ├── my_application.cc
│ ├── my_application.h
│ └── proxy-pin.desktop
├── macos/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── Flutter-Debug.xcconfig
│ │ ├── Flutter-Release.xcconfig
│ │ └── GeneratedPluginRegistrant.swift
│ ├── Podfile
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── AppLifecycleChannel.swift
│ │ ├── Assets.xcassets/
│ │ │ └── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── MainMenu.xib
│ │ ├── Configs/
│ │ │ ├── AppInfo.xcconfig
│ │ │ ├── Debug.xcconfig
│ │ │ ├── Release.xcconfig
│ │ │ └── Warnings.xcconfig
│ │ ├── DebugProfile.entitlements
│ │ ├── Info.plist
│ │ ├── MainFlutterWindow.swift
│ │ ├── Release.entitlements
│ │ └── RunnerProfile.entitlements
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ ├── RunnerTests/
│ │ └── RunnerTests.swift
│ └── packaging/
│ └── dmg/
│ └── make_config.yaml
├── pubspec.yaml
├── test/
│ ├── base64_test.dart
│ ├── cert_test.dart
│ ├── favorites_trim_test.dart
│ ├── http_test.dart
│ ├── js.js
│ ├── js_test.dart
│ ├── pk12_test.dart
│ ├── requests_test.py
│ ├── temp_ipv6_test.dart
│ ├── tests.dart
│ ├── url_test.dart
│ ├── web_test.dart
│ ├── websocket.dart
│ ├── websocket_persistence_test.dart
│ ├── widget_test.dart
│ └── x509_test.dart
└── windows/
├── .gitignore
├── CMakeLists.txt
├── flutter/
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
├── packaging/
│ ├── exe/
│ │ ├── inno_setup.sas
│ │ └── make_config.yaml
│ └── msix/
│ └── make_config.yaml
└── runner/
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
Showing preview only (220K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2796 symbols across 263 files)
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/Protocol.java
type Protocol (line 3) | public enum Protocol {
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/socket/SocketChannelReader.java
class SocketChannelReader (line 29) | class SocketChannelReader {
method SocketChannelReader (line 35) | public SocketChannelReader(ClientPacketWriter writer) {
method read (line 39) | public void read(Connection connection) {
method readTCP (line 79) | private void readTCP(@NonNull Connection connection) {
method sendToRequester (line 113) | private void sendToRequester(ByteBuffer buffer, int dataSize, @NonNull...
method pushDataToClient (line 133) | private void pushDataToClient(@NonNull Connection connection) {
method sendFin (line 166) | private void sendFin(Connection connection) {
method readUDP (line 176) | private void readUDP(Connection connection) {
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/socket/SocketChannelWriter.java
class SocketChannelWriter (line 28) | public class SocketChannelWriter {
method SocketChannelWriter (line 33) | SocketChannelWriter(ClientPacketWriter writer) {
method write (line 37) | public void write(@NonNull Connection connection) {
method writeUDP (line 76) | private void writeUDP(Connection connection) {
method writeTCP (line 91) | private void writeTCP(Connection connection) {
method writePendingData (line 111) | private void writePendingData(Connection connection) throws IOException {
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/socket/SocketNIODataService.java
class SocketNIODataService (line 29) | public class SocketNIODataService implements Runnable {
method SocketNIODataService (line 42) | public SocketNIODataService(ClientPacketWriter clientPacketWriter) thr...
method run (line 47) | @Override
method registerSession (line 53) | public void registerSession(Connection connection) throws ClosedChanne...
method lockSelector (line 77) | private Lock lockSelector(Selector selector) {
method refreshSelect (line 96) | public void refreshSelect(Connection connection) {
method shutdown (line 109) | public void shutdown(){
method runTask (line 114) | private void runTask(){
method processSelectionKey (line 171) | private void processSelectionKey(SelectionKey key) throws IOException {
method isConnected (line 201) | private boolean isConnected(SelectableChannel channel) {
method processConnectedSelection (line 211) | private void processConnectedSelection(SelectionKey key, Connection co...
method processSelectorRead (line 219) | private void processSelectorRead(SelectionKey selectionKey, Connection...
method processPendingWrite (line 229) | private void processPendingWrite(SelectionKey selectionKey, Connection...
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/transport/icmp/ICMPPacket.java
class ICMPPacket (line 6) | public class ICMPPacket {
method ICMPPacket (line 25) | ICMPPacket(
method toString (line 41) | @NonNull
FILE: android/app/src/main/kotlin/com/network/proxy/vpn/transport/icmp/ICMPPacketFactory.java
class ICMPPacketFactory (line 13) | public class ICMPPacketFactory {
method parseICMPPacket (line 15) | public static ICMPPacket parseICMPPacket(@NonNull ByteBuffer stream) {
method buildSuccessPacket (line 29) | public static ICMPPacket buildSuccessPacket(ICMPPacket requestPacket) {
method packetToBuffer (line 40) | public static byte[] packetToBuffer(IP4Header ipHeader, ICMPPacket pac...
method asShortBytes (line 76) | private static byte[] asShortBytes(int value) {
FILE: assets/js/fetch.js
function fetch (line 1) | function fetch(url, options) {
FILE: ios/ProxyPin/vpn/ping/GBPingSummary.h
type GBPingStatus (line 13) | typedef enum {
FILE: ios/ProxyPin/vpn/ping/ICMPHeader.h
type IPHeader (line 20) | struct IPHeader {
type IPHeader (line 34) | typedef struct IPHeader IPHeader;
type ICMPHeader (line 62) | struct ICMPHeader {
type ICMPHeader (line 70) | typedef struct ICMPHeader ICMPHeader;
FILE: lib/l10n/app_localizations.dart
class AppLocalizations (line 64) | abstract class AppLocalizations {
method of (line 69) | AppLocalizations? of(BuildContext context)
method requestRewriteDeleteConfirm (line 673) | String requestRewriteDeleteConfirm(Object size)
method domainListSubtitle (line 925) | String domainListSubtitle(Object count, Object time)
method historyDay (line 1159) | String historyDay(Object day)
method historyRecordTitle (line 1171) | String historyRecordTitle(Object length, Object name)
method historySubtitle (line 1183) | String historySubtitle(Object requestLength, Object size)
method androidRootRename (line 1363) | String androidRootRename(Object name)
method remoteConnected (line 1531) | String remoteConnected(Object os)
method proxyPortRepeat (line 1729) | String proxyPortRepeat(Object port)
class _AppLocalizationsDelegate (line 2188) | class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocaliz...
method load (line 2192) | Future<AppLocalizations> load(Locale locale)
method isSupported (line 2197) | bool isSupported(Locale locale)
method shouldReload (line 2200) | bool shouldReload(_AppLocalizationsDelegate old)
function lookupAppLocalizations (line 2203) | AppLocalizations lookupAppLocalizations(Locale locale)
FILE: lib/l10n/app_localizations_en.dart
class AppLocalizationsEn (line 8) | class AppLocalizationsEn extends AppLocalizations {
method requestRewriteDeleteConfirm (line 297) | String requestRewriteDeleteConfirm(Object size)
method domainListSubtitle (line 426) | String domainListSubtitle(Object count, Object time)
method historyDay (line 545) | String historyDay(Object day)
method historyRecordTitle (line 553) | String historyRecordTitle(Object length, Object name)
method historySubtitle (line 561) | String historySubtitle(Object requestLength, Object size)
method androidRootRename (line 657) | String androidRootRename(Object name)
method remoteConnected (line 745) | String remoteConnected(Object os)
method proxyPortRepeat (line 850) | String proxyPortRepeat(Object port)
FILE: lib/l10n/app_localizations_zh.dart
class AppLocalizationsZh (line 8) | class AppLocalizationsZh extends AppLocalizations {
method requestRewriteDeleteConfirm (line 297) | String requestRewriteDeleteConfirm(Object size)
method domainListSubtitle (line 425) | String domainListSubtitle(Object count, Object time)
method historyDay (line 544) | String historyDay(Object day)
method historyRecordTitle (line 552) | String historyRecordTitle(Object length, Object name)
method historySubtitle (line 560) | String historySubtitle(Object requestLength, Object size)
method androidRootRename (line 653) | String androidRootRename(Object name)
method remoteConnected (line 739) | String remoteConnected(Object os)
method proxyPortRepeat (line 840) | String proxyPortRepeat(Object port)
class AppLocalizationsZhHant (line 1075) | class AppLocalizationsZhHant extends AppLocalizationsZh {
method requestRewriteDeleteConfirm (line 1361) | String requestRewriteDeleteConfirm(Object size)
method domainListSubtitle (line 1489) | String domainListSubtitle(Object count, Object time)
method historyDay (line 1608) | String historyDay(Object day)
method historyRecordTitle (line 1616) | String historyRecordTitle(Object length, Object name)
method historySubtitle (line 1624) | String historySubtitle(Object requestLength, Object size)
method androidRootRename (line 1717) | String androidRootRename(Object name)
method remoteConnected (line 1803) | String remoteConnected(Object os)
method proxyPortRepeat (line 1904) | String proxyPortRepeat(Object port)
FILE: lib/main.dart
function main (line 35) | void main(List<String> args)
class FluentApp (line 63) | class FluentApp extends StatelessWidget {
method build (line 70) | Widget build(BuildContext context)
method theme (line 89) | ThemeData theme(Brightness brightness)
FILE: lib/native/app_lifecycle.dart
class LifecycleListener (line 5) | abstract interface class LifecycleListener {
method onUserLeaveHint (line 6) | void onUserLeaveHint()
method onPictureInPictureModeChanged (line 8) | void onPictureInPictureModeChanged(bool isInPictureInPictureMode)
class AppLifecycleBinding (line 11) | class AppLifecycleBinding {
method ensureInitialized (line 29) | AppLifecycleBinding ensureInitialized()
method addListener (line 33) | void addListener(LifecycleListener listener)
method removeListener (line 38) | void removeListener(LifecycleListener listener)
method _methodCallHandler (line 42) | Future<void> _methodCallHandler(MethodCall call)
FILE: lib/native/installed_apps.dart
class InstalledApps (line 3) | class InstalledApps {
method getInstalledApps (line 6) | Future<List<AppInfo>> getInstalledApps(
method getAppInfo (line 18) | Future<AppInfo> getAppInfo(String packageName)
class AppInfo (line 24) | class AppInfo {
method toJson (line 49) | Map<String, dynamic> toJson()
method toString (line 59) | String toString()
FILE: lib/native/native_method.dart
class NativeMethod (line 4) | class NativeMethod {
method requestLocalNetworkAccess (line 10) | Future<bool> requestLocalNetworkAccess()
method isCaInstalled (line 22) | Future<bool> isCaInstalled(String pem)
method evaluateChainTrusted (line 33) | Future<bool> evaluateChainTrusted(String leafPem, String caPem, {Strin...
FILE: lib/native/pip.dart
class PictureInPicture (line 11) | class PictureInPicture {
method enterPictureInPictureMode (line 31) | Future<bool> enterPictureInPictureMode(String host, int port,
method exitPictureInPictureMode (line 41) | Future<bool> exitPictureInPictureMode()
method addData (line 47) | Future<bool> addData(String text)
FILE: lib/native/process_info.dart
class ProcessInfoPlugin (line 7) | class ProcessInfoPlugin {
method getProcessByPort (line 10) | Future<ProcessInfo?> getProcessByPort(String host, int port)
method getRemoteAddressByPort (line 22) | Future<HostAndPort?> getRemoteAddressByPort(int port)
FILE: lib/native/vpn.dart
class Vpn (line 5) | class Vpn {
method startVpn (line 10) | void startVpn(String host, int port, Configuration configuration, {boo...
method stopVpn (line 31) | void stopVpn()
method restartVpn (line 37) | void restartVpn(String host, int port, Configuration configuration, {b...
method isRunning (line 57) | Future<bool> isRunning()
FILE: lib/network/bin/configuration.dart
class Configuration (line 27) | class Configuration {
method configFile (line 106) | Future<File> configFile()
method flushConfig (line 113) | Future<void> flushConfig()
method _loadConfig (line 127) | Future<Map<String, dynamic>> _loadConfig()
method toJson (line 139) | Map<String, dynamic> toJson()
FILE: lib/network/bin/listener.dart
class EventListener (line 7) | abstract class EventListener {
method onRequest (line 8) | void onRequest(Channel channel, HttpRequest request)
method onResponse (line 10) | void onResponse(ChannelContext channelContext, HttpResponse response)
method onMessage (line 12) | void onMessage(Channel channel, HttpMessage message, WebSocketFrame fr...
class CombinedEventListener (line 16) | class CombinedEventListener extends EventListener {
method onRequest (line 22) | void onRequest(Channel channel, HttpRequest request)
method onResponse (line 29) | void onResponse(ChannelContext channelContext, HttpResponse response)
method onMessage (line 36) | void onMessage(Channel channel, HttpMessage message, WebSocketFrame fr...
FILE: lib/network/bin/server.dart
function main (line 39) | Future<void> main()
class ProxyServer (line 45) | class ProxyServer {
method start (line 81) | Future<Server> start()
method stop (line 118) | Future<Server?> stop()
method setSystemProxyEnable (line 132) | Future<void> setSystemProxyEnable(bool enable)
method restart (line 147) | Future<void> restart()
method retryBind (line 152) | Future<void> retryBind()
method addListener (line 162) | void addListener(EventListener listener)
FILE: lib/network/channel/channel.dart
class ChannelHandler (line 31) | abstract class ChannelHandler<T> {
method channelActive (line 35) | void channelActive(ChannelContext context, Channel channel)
method channelRead (line 38) | Future<void> channelRead(ChannelContext channelContext, Channel channe...
method channelInactive (line 41) | void channelInactive(ChannelContext channelContext, Channel channel)
method exceptionCaught (line 45) | void exceptionCaught(ChannelContext channelContext, Channel channel, d...
class Channel (line 53) | class Channel {
method serverSecureSocket (line 80) | void serverSecureSocket(SecureSocket secureSocket, ChannelContext chan...
method secureSocket (line 87) | Future<SecureSocket> secureSocket(ChannelContext channelContext,
method startSecureSocket (line 99) | Future<SecureSocket> startSecureSocket(ChannelContext channelContext,
method listen (line 109) | void listen(ChannelContext channelContext)
method write (line 118) | Future<void> write(ChannelContext channelContext, Object obj)
method writeBytes (line 123) | Future<void> writeBytes(List<int> bytes)
method writeAndClose (line 155) | Future<void> writeAndClose(ChannelContext channelContext, Object obj)
method close (line 161) | void close()
method toString (line 183) | String toString()
FILE: lib/network/channel/channel_context.dart
class ChannelContext (line 15) | class ChannelContext {
method connectServerChannel (line 33) | Future<Channel> connectServerChannel(HostAndPort hostAndPort, ChannelH...
method startConnect (line 41) | Future<Channel> startConnect(
method getAttribute (line 48) | T? getAttribute<T>(String key)
method putAttribute (line 55) | void putAttribute(String key, Object? value)
method putStreamRequest (line 77) | HttpRequest? putStreamRequest(int streamId, HttpRequest request)
method putStreamResponse (line 83) | void putStreamResponse(int streamId, HttpResponse response)
method getStreamRequest (line 95) | HttpRequest? getStreamRequest(int streamId)
method getStreamResponse (line 99) | HttpResponse? getStreamResponse(int streamId)
method removeStream (line 103) | void removeStream(int streamId)
method put (line 107) | void put(int streamId, HeadersFrame frame)
method removeStreamDependency (line 111) | HeadersFrame? removeStreamDependency(int streamId)
method getStreamDependency (line 115) | HeadersFrame? getStreamDependency(int streamId)
method containsStreamDependency (line 119) | bool containsStreamDependency(int? streamId)
FILE: lib/network/channel/channel_dispatcher.dart
class ChannelDispatcher (line 20) | class ChannelDispatcher extends ChannelHandler<Uint8List> {
method handle (line 30) | void handle(Decoder decoder, Encoder encoder, ChannelHandler handler)
method channelHandle (line 36) | void channelHandle(Codec codec, ChannelHandler handler)
method listen (line 41) | void listen(Channel channel, ChannelContext channelContext)
method channelActive (line 54) | void channelActive(ChannelContext context, Channel channel)
method remoteForward (line 59) | Future<void> remoteForward(ChannelContext channelContext, HostAndPort ...
method relay (line 77) | void relay(ChannelContext channelContext, Channel clientChannel, Chann...
method channelRead (line 88) | Future<void> channelRead(ChannelContext channelContext, Channel channe...
method onError (line 177) | void onError(ChannelContext channelContext, Channel channel, dynamic e...
method onWebSocketHandle (line 187) | void onWebSocketHandle(ChannelContext channelContext, Channel channel,...
method onSseHandle (line 206) | void onSseHandle(ChannelContext channelContext, Channel channel, HttpR...
method notSupportedForward (line 229) | void notSupportedForward(ChannelContext channelContext, Channel channe...
class RawCodec (line 268) | class RawCodec extends Codec<Uint8List, List<int>> {
method decode (line 270) | DecoderResult<Uint8List> decode(ChannelContext channelContext, ByteBuf...
method encode (line 276) | List<int> encode(ChannelContext channelContext, dynamic data)
class ChannelInitializer (line 281) | abstract interface class ChannelInitializer {
method initChannel (line 282) | void initChannel(Channel channel)
FILE: lib/network/channel/host_port.dart
function getHostAndPort (line 21) | HostAndPort getHostAndPort(HttpRequest request, {bool? ssl})
class HostAndPort (line 30) | class HostAndPort {
method _isIPv6 (line 65) | bool _isIPv6(String address)
method startsWithScheme (line 76) | bool startsWithScheme(String url)
method isSsl (line 80) | bool isSsl()
method of (line 85) | HostAndPort of(String url, {bool? ssl})
method copyWith (line 128) | HostAndPort copyWith({String? scheme, String? host, int? port})
method toString (line 145) | String toString()
class ProxyInfo (line 151) | class ProxyInfo {
method toJson (line 178) | Map<String, dynamic> toJson()
method toString (line 190) | String toString()
FILE: lib/network/channel/network.dart
class Network (line 38) | abstract class Network {
method initChannel (line 41) | Network initChannel(void Function(Channel channel) initializer)
method listen (line 46) | Channel listen(Channel channel, ChannelContext channelContext)
method onEvent (line 62) | Future<void> onEvent(Uint8List data, ChannelContext channelContext, Ch...
method relay (line 65) | void relay(Channel clientChannel, Channel remoteChannel)
class Server (line 72) | class Server extends Network {
method bind (line 84) | Future<ServerSocket> bind(int port)
method stop (line 109) | Future<ServerSocket> stop()
method cleanupConnections (line 131) | void cleanupConnections()
method onEvent (line 142) | Future<void> onEvent(Uint8List data, ChannelContext channelContext, Ch...
method ssl (line 186) | void ssl(ChannelContext channelContext, Channel channel, Uint8List data)
class Client (line 262) | class Client extends Network {
method connect (line 263) | Future<Channel> connect(HostAndPort hostAndPort, ChannelContext channe...
method secureConnect (line 283) | Future<Channel> secureConnect(HostAndPort hostAndPort, ChannelContext ...
method onEvent (line 293) | Future<void> onEvent(Uint8List data, ChannelContext channelContext, Ch...
FILE: lib/network/components/host_filter.dart
function main (line 17) | void main()
class HostFilter (line 23) | class HostFilter {
method filter (line 31) | bool filter(String? host)
class HostList (line 49) | abstract class HostList {
method load (line 55) | void load(Map<String, dynamic>? map)
method add (line 67) | void add(String reg)
method remove (line 73) | void remove(String reg)
method removeIndex (line 77) | void removeIndex(List<int> index)
method toJson (line 84) | Map<String, dynamic> toJson()
class Whites (line 93) | class Whites extends HostList {}
class Blacks (line 96) | class Blacks extends HostList {
FILE: lib/network/components/hosts.dart
class Hosts (line 25) | class Hosts extends Interceptor {
method preConnect (line 32) | Future<HostAndPort> preConnect(HostAndPort hostAndPort)
FILE: lib/network/components/interceptor.dart
class Interceptor (line 6) | abstract class Interceptor {
method preConnect (line 10) | Future<HostAndPort> preConnect(HostAndPort hostAndPort)
method execute (line 15) | Future<HttpResponse?> execute(HttpRequest request)
method onRequest (line 20) | Future<HttpRequest?> onRequest(HttpRequest request)
method onResponse (line 25) | Future<HttpResponse?> onResponse(HttpRequest request, HttpResponse res...
method onError (line 29) | Future<void> onError(HttpRequest? request, dynamic error, StackTrace? ...
FILE: lib/network/components/js/file.dart
class FileBridge (line 25) | class FileBridge {
method registerFile (line 90) | void registerFile(JavascriptRuntime flutterJs)
FILE: lib/network/components/js/md5.dart
class Md5Bridge (line 25) | class Md5Bridge {
method registerMd5 (line 33) | void registerMd5(JavascriptRuntime flutterJs)
FILE: lib/network/components/js/script_engine.dart
class JavaScriptEngine (line 16) | class JavaScriptEngine {
method getJavaScript (line 17) | Future<JavascriptRuntime> getJavaScript({Function(dynamic args)? conso...
method jsResultResolve (line 33) | Future<dynamic> jsResultResolve(JavascriptRuntime flutterJs, JsEvalRes...
method convertJsRequest (line 61) | Future<Map<String, dynamic>> convertJsRequest(HttpRequest request)
method convertJsResponse (line 76) | Future<Map<String, dynamic>> convertJsResponse(HttpResponse response)
method convertHttpRequest (line 91) | HttpRequest convertHttpRequest(HttpRequest request, Map<dynamic, dynam...
method convertHttpResponse (line 129) | HttpResponse convertHttpResponse(HttpResponse response, Map<dynamic, d...
FILE: lib/network/components/js/xhr.dart
function setXhrDebug (line 33) | setXhrDebug(bool value)
type HttpMethod (line 42) | enum HttpMethod { put, get, post, delete, patch, head }
function _debugSendNativeCallback (line 44) | String _debugSendNativeCallback()
class XhrPendingCall (line 211) | class XhrPendingCall {
function xhrSetHttpClient (line 231) | xhrSetHttpClient(http.Client client)
function getPendingXhrCalls (line 236) | List<dynamic>? getPendingXhrCalls()
function hasPendingXhrCalls (line 240) | bool hasPendingXhrCalls()
function clearXhrPendingCalls (line 242) | void clearXhrPendingCalls()
function enableFetch2 (line 246) | Future<void> enableFetch2({bool enabledProxy = false})
function createClient (line 253) | Future<http.Client> createClient(bool enabledProxy)
function enableXhr2 (line 285) | void enableXhr2({bool enabledProxy = false})
class XhtmlHttpResponseInfo (line 444) | class XhtmlHttpResponseInfo {
method addResponseHeaders (line 456) | void addResponseHeaders(String name, String value)
method toJson (line 460) | Map<String, Object?> toJson()
class XmlHttpRequestResponse (line 470) | class XmlHttpRequestResponse {
method toJson (line 477) | Map<String, Object?> toJson()
FILE: lib/network/components/manager/hosts_manager.dart
class HostsManager (line 26) | class HostsManager {
method homePath (line 48) | Future<String> homePath()
method load (line 68) | Future<void> load()
method flushConfig (line 92) | Future<void> flushConfig()
method getFolderList (line 105) | List<HostsItem> getFolderList(String parent)
method addHosts (line 109) | Future<void> addHosts(HostsItem item)
method getHosts (line 118) | Future<HostsItem?> getHosts(String host)
class HostsItem (line 160) | class HostsItem {
method generateId (line 172) | String generateId()
method match (line 177) | bool match(String domain)
method toJson (line 194) | Map<String, dynamic> toJson()
FILE: lib/network/components/manager/report_server_manager.dart
class ReportServerManager (line 6) | class ReportServerManager {
method matchServer (line 26) | Future<ReportServer?> matchServer(String url)
method add (line 36) | Future<void> add(ReportServer server)
method removeAt (line 41) | Future<void> removeAt(int index)
method update (line 47) | Future<void> update(int index, ReportServer server)
method toggleEnabled (line 54) | Future<void> toggleEnabled(int index, bool enabled)
method loadConfig (line 60) | Future<void> loadConfig()
method _flush (line 78) | Future<void> _flush()
class ReportServer (line 85) | class ReportServer {
method match (line 109) | bool match(String url)
method updateUrlReg (line 116) | void updateUrlReg()
method copyWith (line 120) | ReportServer copyWith({
method toJson (line 148) | Map<String, dynamic> toJson()
FILE: lib/network/components/manager/request_block_manager.dart
class RequestBlockManager (line 25) | class RequestBlockManager {
method configFile (line 43) | Future<File> configFile()
method _load (line 53) | Future<void> _load()
method enableBlockRequest (line 75) | bool enableBlockRequest(String url)
method enableBlockResponse (line 82) | bool enableBlockResponse(String url)
method flushConfig (line 90) | Future<void> flushConfig()
type BlockType (line 95) | enum BlockType {
class RequestBlockItem (line 108) | class RequestBlockItem {
method match (line 117) | bool match(String url, BlockType blockType)
method toJson (line 126) | Map<String, dynamic> toJson()
method toString (line 131) | String toString()
FILE: lib/network/components/manager/request_breakpoint_manager.dart
class RequestBreakpointRule (line 9) | class RequestBreakpointRule {
method match (line 29) | bool match(String url, {HttpMethod? method})
method toJson (line 55) | Map<String, dynamic> toJson()
class RequestBreakpointManager (line 67) | class RequestBreakpointManager {
method homePath (line 83) | Future<String> homePath()
method load (line 90) | Future<void> load()
method save (line 104) | Future<void> save()
method add (line 121) | void add(RequestBreakpointRule rule)
method remove (line 126) | void remove(RequestBreakpointRule rule)
FILE: lib/network/components/manager/request_crypto_manager.dart
class RequestCryptoManager (line 8) | class RequestCryptoManager {
method _reload (line 27) | Future<void> _reload(Map<String, dynamic>? map)
method reloadConfig (line 44) | Future<void> reloadConfig()
method _loadRequestCryptoConfig (line 49) | Future<Map<String, dynamic>?> _loadRequestCryptoConfig()
method flushConfig (line 65) | Future<void> flushConfig()
method getMatchingRule (line 77) | CryptoRule? getMatchingRule(HttpMessage message)
method addRule (line 89) | Future<void> addRule(CryptoRule rule)
method updateRule (line 94) | Future<void> updateRule(int index, CryptoRule rule)
method removeRule (line 100) | Future<void> removeRule(int index)
method removeIndex (line 106) | Future<void> removeIndex(List<int> indexes)
method toJson (line 115) | Map<String, Object> toJson()
class CryptoRule (line 121) | class CryptoRule {
method matches (line 136) | bool matches(String url)
method toJson (line 144) | Map<String, dynamic> toJson()
method copyWith (line 165) | CryptoRule copyWith({
method newRule (line 182) | CryptoRule newRule()
class CryptoKeyConfig (line 193) | class CryptoKeyConfig {
method copyWith (line 225) | CryptoKeyConfig copyWith({
method toJson (line 245) | Map<String, Object?> toJson()
FILE: lib/network/components/manager/request_map_manager.dart
class RequestMapManager (line 10) | class RequestMapManager {
method addRule (line 34) | Future<void> addRule(RequestMapRule rule, RequestMapItem item)
method updateRule (line 50) | Future<void> updateRule(RequestMapRule rule, RequestMapItem item)
method deleteRule (line 62) | Future<void> deleteRule(int index)
method findMatch (line 69) | RequestMapRule? findMatch(String url)
method getMapItem (line 78) | Future<RequestMapItem?> getMapItem(RequestMapRule rule)
method homePath (line 100) | Future<String> homePath()
method reloadConfig (line 123) | Future<void> reloadConfig()
method flushConfig (line 144) | Future<void> flushConfig()
type RequestMapType (line 159) | enum RequestMapType {
class RequestMapRule (line 174) | class RequestMapRule {
method match (line 186) | bool match(String url)
method updatePathReg (line 203) | void updatePathReg()
method toJson (line 207) | Map<String, Object?> toJson()
class RequestMapItem (line 218) | class RequestMapItem {
method toJson (line 245) | Map<String, Object?> toJson()
type MapBodyType (line 257) | enum MapBodyType {
FILE: lib/network/components/manager/request_rewrite_manager.dart
class RequestRewriteManager (line 29) | class RequestRewriteManager {
method reload (line 53) | Future<void> reload(Map<String, dynamic>? map)
method reloadRequestRewrite (line 72) | Future<void> reloadRequestRewrite()
method syncConfig (line 78) | Future<void> syncConfig(Map<String, dynamic>? config)
method _loadRequestRewriteConfig (line 101) | Future<Map<String, dynamic>?> _loadRequestRewriteConfig()
method flushRequestRewriteConfig (line 115) | Future<void> flushRequestRewriteConfig()
method addRule (line 128) | Future<void> addRule(RequestRewriteRule rule, List<RewriteItem> items)
method updateRule (line 142) | Future<void> updateRule(int index, RequestRewriteRule rule, List<Rewri...
method removeIndex (line 166) | Future<void> removeIndex(List<int> indexes)
method getRequestRewriteRule (line 182) | RequestRewriteRule getRequestRewriteRule(HttpRequest request, RuleType...
method getRewriteRule (line 193) | RequestRewriteRule? getRewriteRule(String? url, List<RuleType> types)
method getRewriteItems (line 206) | Future<List<RewriteItem>?> getRewriteItems(RequestRewriteRule rule)
method toJson (line 227) | Map<String, Object> toJson()
method toFullJson (line 234) | Future<Map<String, dynamic>> toFullJson()
FILE: lib/network/components/manager/rewrite_rule.dart
type RuleType (line 22) | enum RuleType {
class RequestRewriteRule (line 41) | class RequestRewriteRule {
method match (line 56) | bool match(String url, {RuleType? type, HttpMethod? method})
method matchUrl (line 66) | bool matchUrl(String url, RuleType type)
method updatePathReg (line 90) | void updatePathReg()
method toJson (line 94) | Map<String, dynamic> toJson()
type ReplaceBodyType (line 111) | enum ReplaceBodyType {
class RewriteItem (line 120) | class RewriteItem {
method fromRequest (line 137) | List<RewriteItem> fromRequest(HttpRequest request)
method fromResponse (line 146) | List<RewriteItem> fromResponse(HttpResponse response)
method toJson (line 208) | Map<String, dynamic> toJson()
method toString (line 217) | String toString()
type RewriteType (line 222) | enum RewriteType {
FILE: lib/network/components/manager/script_manager.dart
class ScriptManager (line 35) | class ScriptManager {
method registerConsoleLog (line 87) | void registerConsoleLog(int fromWindowId)
method registerLogHandler (line 99) | void registerLogHandler(LogHandler logHandler)
method removeLogHandler (line 106) | void removeLogHandler(int channelId)
method consoleLog (line 110) | dynamic consoleLog(dynamic args)
method reloadScript (line 125) | Future<void> reloadScript()
method homePath (line 147) | Future<String> homePath()
method getScript (line 169) | Future<String?> getScript(ScriptItem item)
method _fetchRemoteScript (line 190) | Future<String?> _fetchRemoteScript(ScriptItem item)
method _isHttpUrl (line 206) | bool _isHttpUrl(String url)
method addScript (line 213) | Future<void> addScript(ScriptItem item, String? script)
method updateScript (line 232) | Future<void> updateScript(ScriptItem item, String script)
method removeScript (line 249) | Future<void> removeScript(int index)
method clean (line 259) | Future<void> clean()
method flushConfig (line 272) | Future<void> flushConfig()
method scriptContext (line 279) | Map<String, dynamic> scriptContext(ScriptItem item)
method runScript (line 284) | Future<HttpRequest?> runScript(HttpRequest request)
method runResponseScript (line 313) | Future<HttpResponse?> runResponseScript(HttpResponse response)
class LogHandler (line 346) | class LogHandler {
class LogInfo (line 353) | class LogInfo {
method toJson (line 364) | Map<String, dynamic> toJson()
method toString (line 369) | String toString()
class ScriptItem (line 374) | class ScriptItem {
method match (line 389) | bool match(String url)
method toJson (line 417) | Map<String, dynamic> toJson()
method toString (line 428) | String toString()
FILE: lib/network/components/report_server_interceptor.dart
class ReportServerInterceptor (line 31) | class ReportServerInterceptor extends Interceptor {
method onResponse (line 40) | Future<HttpResponse?> onResponse(HttpRequest request, HttpResponse res...
method onError (line 47) | Future<void> onError(HttpRequest? request, error, StackTrace? stackTrace)
method reportServer (line 54) | Future<void> reportServer(HttpRequest request, HttpResponse? response,
FILE: lib/network/components/request_block.dart
class RequestBlockInterceptor (line 25) | class RequestBlockInterceptor extends Interceptor {
method onRequest (line 30) | Future<HttpRequest?> onRequest(HttpRequest request)
method onResponse (line 41) | Future<HttpResponse?> onResponse(HttpRequest request, HttpResponse res...
FILE: lib/network/components/request_breakpoint.dart
class RequestBreakpointInterceptor (line 12) | class RequestBreakpointInterceptor extends Interceptor {
method onRequest (line 23) | Future<HttpRequest?> onRequest(HttpRequest request)
method onResponse (line 65) | Future<HttpResponse?> onResponse(HttpRequest request, HttpResponse res...
method resumeRequest (line 103) | void resumeRequest(String requestId, HttpRequest? request)
method resumeResponse (line 109) | void resumeResponse(String requestId, HttpResponse? response)
FILE: lib/network/components/request_map.dart
class RequestMapInterceptor (line 31) | class RequestMapInterceptor extends Interceptor {
method scriptContext (line 41) | Map<String, dynamic> scriptContext(RequestMapRule rule)
method execute (line 46) | Future<HttpResponse?> execute(HttpRequest request)
method mapLocalResponse (line 78) | Future<HttpResponse> mapLocalResponse(RequestMapRule rule, RequestMapI...
method executeScript (line 94) | Future<HttpResponse?> executeScript(HttpRequest request, RequestMapRul...
FILE: lib/network/components/request_rewrite.dart
class RequestRewriteInterceptor (line 34) | class RequestRewriteInterceptor extends Interceptor {
method onRequest (line 42) | Future<HttpRequest?> onRequest(HttpRequest request)
method onResponse (line 50) | Future<HttpResponse?> onResponse(HttpRequest request, HttpResponse res...
method getRedirectRule (line 63) | Future<String?> getRedirectRule(String? url)
method requestRewrite (line 80) | Future<void> requestRewrite(String url, HttpRequest request)
method responseRewrite (line 107) | Future<void> responseRewrite(String? url, HttpResponse response)
method _updateRequest (line 138) | Future<void> _updateRequest(HttpRequest request, RewriteItem item)
method _updateMessage (line 194) | Future<void> _updateMessage(HttpMessage message, RewriteItem item)
method _replaceRequest (line 246) | Future<void> _replaceRequest(HttpRequest request, RewriteItem item)
method _replaceResponse (line 261) | Future<void> _replaceResponse(HttpResponse response, RewriteItem item)
method _replaceHttpMessage (line 269) | Future<void> _replaceHttpMessage(HttpMessage message, RewriteItem item)
FILE: lib/network/components/script.dart
class ScriptInterceptor (line 25) | class ScriptInterceptor extends Interceptor {
method onRequest (line 30) | Future<HttpRequest?> onRequest(HttpRequest request)
method onResponse (line 41) | Future<HttpResponse?> onResponse(HttpRequest request, HttpResponse res...
FILE: lib/network/handle/http_proxy_handle.dart
class HttpProxyChannelHandler (line 20) | class HttpProxyChannelHandler extends ChannelHandler<HttpRequest> {
method channelRead (line 28) | Future<void> channelRead(ChannelContext channelContext, Channel channe...
method exceptionCaught (line 52) | void exceptionCaught(ChannelContext channelContext, Channel channel, e...
method channelInactive (line 61) | void channelInactive(ChannelContext channelContext, Channel channel)
method forward (line 68) | Future<void> forward(ChannelContext channelContext, Channel channel, H...
method redirect (line 147) | Future<void> redirect(
method _getRemoteChannel (line 166) | Future<Channel> _getRemoteChannel(
method connectRemote (line 236) | Future<Channel> connectRemote(ChannelContext channelContext, Channel c...
class HttpResponseProxyHandler (line 244) | class HttpResponseProxyHandler extends ChannelHandler<HttpResponse> {
method channelRead (line 254) | Future<void> channelRead(ChannelContext channelContext, Channel channe...
method channelInactive (line 287) | void channelInactive(ChannelContext channelContext, Channel channel)
method exceptionCaught (line 292) | void exceptionCaught(ChannelContext channelContext, Channel channel, e...
FILE: lib/network/handle/relay_handle.dart
class RelayHandler (line 4) | class RelayHandler extends ChannelHandler<Object> {
method channelRead (line 10) | Future<void> channelRead(ChannelContext channelContext, Channel channe...
method channelInactive (line 16) | void channelInactive(ChannelContext channelContext, Channel channel)
FILE: lib/network/handle/sse_handle.dart
class SseChannelHandler (line 11) | class SseChannelHandler extends ChannelHandler<Uint8List> {
method channelRead (line 20) | Future<void> channelRead(ChannelContext channelContext, Channel channe...
FILE: lib/network/handle/websocket_handle.dart
class WebSocketChannelHandler (line 10) | class WebSocketChannelHandler extends ChannelHandler<Uint8List> {
method channelRead (line 19) | Future<void> channelRead(ChannelContext channelContext, Channel channe...
FILE: lib/network/http/codec.dart
class ParserException (line 31) | class ParserException implements Exception {
method toString (line 38) | String toString()
type State (line 43) | enum State {
class DecoderResult (line 50) | class DecoderResult<T> {
class Decoder (line 62) | abstract interface class Decoder<T> {
method decode (line 64) | DecoderResult<T> decode(ChannelContext channelContext, ByteBuf byteBuf)
class Encoder (line 68) | abstract interface class Encoder<T> {
method encode (line 69) | List<int> encode(ChannelContext channelContext, T data)
class Codec (line 73) | abstract class Codec<D, E> implements Decoder<D>, Encoder<E> {
class HttpCodec (line 79) | abstract class HttpCodec<T extends HttpMessage> implements Codec<T, T> {
method createMessage (line 88) | T createMessage(List<String> reqLine)
method getH2Codec (line 90) | Http2Codec<T> getH2Codec()
method decode (line 95) | DecoderResult<T> decode(ChannelContext channelContext, ByteBuf data)
method init (line 150) | void init()
method initialLine (line 155) | void initialLine(BytesBuilder buffer, T message)
method encode (line 158) | List<int> encode(ChannelContext channelContext, T message)
method _readInitialLine (line 199) | List<String> _readInitialLine(ByteBuf data)
method _readHeader (line 205) | void _readHeader(ByteBuf data, T message)
method _convertBody (line 213) | List<int>? _convertBody(List<int>? bytes)
class HttpRequestCodec (line 222) | class HttpRequestCodec extends HttpCodec<HttpRequest> {
method createMessage (line 224) | HttpRequest createMessage(List<String> reqLine)
method initialLine (line 230) | void initialLine(BytesBuilder buffer, HttpRequest message)
class HttpResponseCodec (line 252) | class HttpResponseCodec extends HttpCodec<HttpResponse> {
method createMessage (line 254) | HttpResponse createMessage(List<String> reqLine)
method initialLine (line 260) | void initialLine(BytesBuilder buffer, HttpResponse message)
class HttpServerCodec (line 272) | class HttpServerCodec extends Codec<HttpRequest, HttpResponse> {
method decode (line 277) | DecoderResult<HttpRequest> decode(ChannelContext channelContext, ByteB...
method encode (line 282) | List<int> encode(ChannelContext channelContext, HttpResponse data)
class HttpClientCodec (line 287) | class HttpClientCodec extends Codec<HttpResponse, HttpRequest> {
method decode (line 292) | DecoderResult<HttpResponse> decode(ChannelContext channelContext, Byte...
method encode (line 297) | List<int> encode(ChannelContext channelContext, HttpRequest data)
FILE: lib/network/http/constants.dart
class HttpConstants (line 1) | class HttpConstants {
FILE: lib/network/http/content_type.dart
type ContentType (line 22) | enum ContentType {
class MediaType (line 50) | class MediaType {
method valueOf (line 79) | MediaType? valueOf(String mediaType)
method defaultCharset (line 103) | String? defaultCharset(MediaType mediaType)
method _parseMediaTypeInternal (line 112) | MediaType? _parseMediaTypeInternal(String mediaType)
method equalsTypeAndSubtype (line 178) | bool equalsTypeAndSubtype(MediaType other)
class InvalidMediaTypeException (line 197) | class InvalidMediaTypeException implements Exception {
method toString (line 204) | String toString()
FILE: lib/network/http/h2/frame.dart
type FrameType (line 17) | enum FrameType { data, headers, priority, rstStream, settings, pushPromi...
class FrameHeader (line 19) | class FrameHeader {
method encode (line 41) | List<int> encode()
method _intToBytes (line 50) | List<int> _intToBytes(int value, int byteCount)
class Frame (line 60) | class Frame {
method toJson (line 65) | Map toJson()
class HeadersFrame (line 73) | class HeadersFrame extends Frame {
method toString (line 84) | String toString()
class DataFrame (line 89) | class DataFrame extends Frame {
FILE: lib/network/http/h2/h2_codec.dart
class Http2Codec (line 36) | abstract class Http2Codec<T extends HttpMessage> implements Codec<T, T> {
method createMessage (line 45) | T createMessage(ChannelContext channelContext, FrameHeader frameHeader...
method getMessage (line 47) | T? getMessage(ChannelContext channelContext, FrameHeader frameHeader)
method decode (line 53) | DecoderResult<T> decode(ChannelContext channelContext, ByteBuf byteBuf...
method parseHttp2Packet (line 107) | DecoderResult<T> parseHttp2Packet(ChannelContext channelContext, Frame...
method encodeHeaders (line 201) | List<Header> encodeHeaders(T message)
method encode (line 204) | Uint8List encode(ChannelContext channelContext, T data)
method writeHeadersFrame (line 233) | void writeHeadersFrame(
method _writeHeadersFrame (line 272) | void _writeHeadersFrame(
method _writeFrame (line 296) | void _writeFrame(ChannelContext channelContext, BytesBuilder bytesBuil...
method isConnectionPrefacePRI (line 306) | bool isConnectionPrefacePRI(ByteBuf data)
method _handleSseDataFrame (line 318) | void _handleSseDataFrame(
method _handleDataFrame (line 344) | DataFrame _handleDataFrame(
method _handleHeadersFrame (line 366) | HeadersFrame _handleHeadersFrame(ChannelContext channelContext, FrameH...
method _parseHeaders (line 416) | Map<String, List<String>> _parseHeaders(ChannelContext channelContext,...
class Http2RequestDecoder (line 437) | class Http2RequestDecoder extends Http2Codec<HttpRequest> {
method createMessage (line 439) | HttpRequest createMessage(ChannelContext channelContext, FrameHeader f...
method getMessage (line 482) | HttpRequest? getMessage(ChannelContext channelContext, FrameHeader fra...
method encodeHeaders (line 487) | List<Header> encodeHeaders(HttpRequest message)
class Http2ResponseDecoder (line 504) | class Http2ResponseDecoder extends Http2Codec<HttpResponse> {
method createMessage (line 506) | HttpResponse createMessage(
method getMessage (line 519) | HttpResponse? getMessage(ChannelContext channelContext, FrameHeader fr...
method encodeHeaders (line 524) | List<Header> encodeHeaders(HttpResponse message)
class FrameReader (line 536) | class FrameReader {
method _readFramePayload (line 539) | List<int>? _readFramePayload(ByteBuf data, int length)
method readFrameHeader (line 549) | FrameHeader? readFrameHeader(ByteBuf data)
FILE: lib/network/http/h2/hpack/hpack.dart
class HPackDecodingException (line 16) | class HPackDecodingException implements Exception {
method toString (line 22) | String toString()
class HPackContext (line 28) | class HPackContext {
class Header (line 42) | class Header {
class HPackDecoder (line 63) | class HPackDecoder {
method updateMaxReceivingHeaderTableSize (line 68) | void updateMaxReceivingHeaderTableSize(int newMaximumSize)
method decode (line 72) | List<Header> decode(List<int> data)
method readInteger (line 75) | int readInteger(int prefixBits)
method readStringLiteral (line 100) | List<int> readStringLiteral()
method readHeaderFieldInternal (line 113) | Header readHeaderFieldInternal(int index, {bool neverIndexed = false})
class HPackEncoder (line 171) | class HPackEncoder {
method updateMaxSendingHeaderTableSize (line 172) | void updateMaxSendingHeaderTableSize(int newMaximumSize)
method encode (line 177) | List<int> encode(List<Header> headers)
method writeInteger (line 181) | void writeInteger(int prefixBits, int value)
method writeStringLiteral (line 204) | void writeStringLiteral(List<int> bytes)
method writeLiteralHeaderWithoutIndexing (line 211) | void writeLiteralHeaderWithoutIndexing(Header header)
class IndexTable (line 225) | class IndexTable {
method updateMaxSize (line 303) | void updateMaxSize(int newMaxDynTableSize)
method lookup (line 309) | Header lookup(int index)
method addHeaderField (line 329) | void addHeaderField(Header header)
method _reduce (line 337) | void _reduce()
method _sizeOf (line 347) | int _sizeOf(Header header)
FILE: lib/network/http/h2/hpack/huffman.dart
class HuffmanDecodingException (line 9) | class HuffmanDecodingException implements Exception {
method toString (line 15) | String toString()
class HuffmanCodec (line 19) | class HuffmanCodec {
method decode (line 25) | List<int> decode(List<int> bytes)
method encode (line 27) | List<int> encode(List<int> bytes)
class HuffmanDecoder (line 31) | class HuffmanDecoder {
method decode (line 37) | List<int> decode(List<int> bytes)
class HuffmanEncoder (line 89) | class HuffmanEncoder {
method encode (line 95) | List<int> encode(List<int> bytes)
method writeValue (line 101) | void writeValue(int value, int numBits)
class EncodedHuffmanValue (line 140) | class EncodedHuffmanValue {
class HuffmanTreeNode (line 151) | class HuffmanTreeNode {
function generateHuffmanTree (line 158) | HuffmanTreeNode generateHuffmanTree(List<EncodedHuffmanValue> valueEncod...
FILE: lib/network/http/h2/setting.dart
class StreamSetting (line 21) | class StreamSetting {
class SettingHandler (line 44) | class SettingHandler {
method handleSettingsFrame (line 45) | void handleSettingsFrame(ChannelContext channelContext, FrameHeader fr...
FILE: lib/network/http/http.dart
class HttpMessage (line 31) | abstract class HttpMessage {
method toJson (line 80) | Map<String, dynamic> toJson()
method getBodyString (line 116) | String getBodyString({String? charset})
method decodeBodyString (line 149) | Future<String> decodeBodyString()
class HttpRequest (line 178) | class HttpRequest extends HttpMessage {
method remoteDomain (line 197) | String? remoteDomain()
method copy (line 254) | HttpRequest copy({String? uri})
method toJson (line 268) | Map<String, dynamic> toJson()
method toString (line 305) | String toString()
class HttpResponse (line 311) | class HttpResponse extends HttpMessage {
method copy (line 323) | HttpResponse copy()
method costTime (line 332) | String costTime()
method toJson (line 364) | Map<String, dynamic> toJson()
method toString (line 382) | String toString()
type HttpMethod (line 388) | enum HttpMethod {
class HttpStatus (line 421) | class HttpStatus {
method newStatus (line 449) | HttpStatus newStatus(int statusCode, String? reasonPhrase)
method valueOf (line 457) | HttpStatus valueOf(int code)
method reason (line 484) | HttpStatus reason(String reasonPhrase)
method isSuccessful (line 491) | bool isSuccessful()
method toString (line 496) | String toString()
FILE: lib/network/http/http_client.dart
class HttpClients (line 39) | class HttpClients {
method startConnect (line 40) | Future<Channel> startConnect(HostAndPort hostAndPort, {Duration timeou...
method proxyConnect (line 56) | Future<Channel> proxyConnect(
method connectRequest (line 91) | Future<Channel> connectRequest(ChannelContext channelContext, HostAndP...
method connect (line 121) | Future<Channel> connect(Uri uri, ChannelHandler handler, ChannelContex...
method get (line 132) | Future<HttpResponse> get(String url, {Duration timeout = const Duratio...
method request (line 138) | Future<HttpResponse> request(HostAndPort hostAndPort, HttpRequest requ...
method proxyRequest (line 154) | Future<HttpResponse> proxyRequest(HttpRequest request,
class Http2ClientHandler (line 184) | class Http2ClientHandler {
method listen (line 193) | Future<void> listen(Channel channel, ChannelContext channelContext)
method onData (line 234) | void onData(ChannelContext channelContext, Channel channel, Uint8List ...
class HttpResponseHandler (line 265) | class HttpResponseHandler extends ChannelHandler<HttpResponse> {
method channelRead (line 269) | Future<void> channelRead(ChannelContext channelContext, Channel channe...
method getResponse (line 274) | Future<HttpResponse> getResponse(Duration duration)
method resetResponse (line 278) | void resetResponse()
FILE: lib/network/http/http_headers.dart
class HttpHeaders (line 21) | class HttpHeaders {
method set (line 116) | void set(String name, String value)
method add (line 127) | void add(String name, String value)
method addValues (line 132) | void addValues(String name, List<String> values)
method get (line 155) | String? get(String name)
method getOriginalName (line 159) | String getOriginalName(String name)
method getList (line 163) | List<String>? getList(String name)
method remove (line 171) | bool remove(String name)
method getInt (line 177) | int? getInt(String name)
method getBool (line 185) | bool getBool(String name)
method forEach (line 205) | void forEach(void Function(String name, List<String> values) f)
method clear (line 224) | void clear()
method headerLines (line 229) | String headerLines()
method toJson (line 241) | Map<String, dynamic> toJson()
method toMap (line 250) | Map<String, String> toMap()
method getHeaders (line 258) | Map<String, List<String>> getHeaders()
method toRawHeaders (line 275) | String toRawHeaders()
method toString (line 287) | String toString()
FILE: lib/network/http/parse/body_reader.dart
class Result (line 26) | class Result {
class BodyReader (line 35) | class BodyReader {
method readBody (line 50) | Result readBody(Uint8List data)
method _readFixedLengthContent (line 79) | void _readFixedLengthContent(Uint8List data)
method _readChunked (line 89) | void _readChunked(Uint8List data)
method _readChunkSize (line 123) | int _readChunkSize(Uint8List data)
type ReaderState (line 152) | enum ReaderState { readFixedLengthContent, readChunked, readChunkSize, r...
FILE: lib/network/http/parse/http_parser.dart
class HttpParse (line 8) | class HttpParse {
method parseInitialLine (line 12) | List<String> parseInitialLine(ByteBuf data, int size)
method _splitLine (line 38) | List<String> _splitLine(Uint8List data)
method parseHeaders (line 55) | bool parseHeaders(ByteBuf data, HttpHeaders headers)
method _isLineEnd (line 82) | bool _isLineEnd(ByteBuf data, int index)
method _splitHeader (line 87) | List<String> _splitHeader(List<int> data)
FILE: lib/network/http/sse.dart
class SseDecoder (line 12) | class SseDecoder {
method feed (line 22) | List<WebSocketFrame> feed(Uint8List bytes)
method _resetEventState (line 89) | void _resetEventState()
method _buildLabeledPayload (line 96) | String _buildLabeledPayload(String data, {String? event, String? id, i...
method _textFrame (line 105) | WebSocketFrame _textFrame(String text)
FILE: lib/network/http/websocket.dart
class WebSocketFrame (line 23) | class WebSocketFrame {
method toJson (line 73) | Map<String, dynamic> toJson()
class WebSocketDecoder (line 106) | class WebSocketDecoder {
method decode (line 109) | WebSocketFrame? decode(Uint8List newData)
method canParseWebSocketFrame (line 125) | bool canParseWebSocketFrame(Uint8List data)
method _parseWebSocketFrame (line 165) | WebSocketFrame _parseWebSocketFrame(Uint8List data)
method _ensureDecoder (line 222) | ZLibDecoder _ensureDecoder()
method decompress (line 224) | Uint8List decompress(Uint8List msg)
method unmaskPayload (line 233) | Uint8List unmaskPayload(Uint8List payloadData, int maskingKey)
class ByteBuffer (line 243) | class ByteBuffer {
method putBytes (line 248) | void putBytes(Uint8List newBytes)
method clear (line 255) | void clear()
FILE: lib/network/socks/socks5.dart
class Socks5 (line 29) | class Socks5 {
method isSocks5 (line 48) | bool isSocks5(Uint8List data)
class SocksServerHandler (line 57) | class SocksServerHandler extends ChannelHandler<Uint8List> {
method channelRead (line 67) | Future<void> channelRead(ChannelContext channelContext, Channel channe...
method encodeCommandResponse (line 133) | Uint8List encodeCommandResponse(int status, {int bndAddrType = 0, Stri...
type SocksState (line 151) | enum SocksState {
FILE: lib/network/util/attribute_keys.dart
class AttributeKeys (line 3) | interface class AttributeKeys {
FILE: lib/network/util/byte_buf.dart
class ByteBuf (line 21) | class ByteBuf {
method add (line 39) | void add(List<int> bytes)
method clear (line 45) | void clear()
method clearRead (line 52) | void clearRead()
method isReadable (line 65) | bool isReadable()
method readableBytes (line 67) | int readableBytes()
method readAvailableBytes (line 69) | Uint8List readAvailableBytes()
method readBytes (line 71) | Uint8List readBytes(int length)
method skipBytes (line 77) | void skipBytes(int length)
method read (line 81) | int read()
method readByte (line 83) | int readByte()
method readShort (line 85) | int readShort()
method readInt (line 91) | int readInt()
method get (line 100) | int get(int index)
method truncate (line 102) | void truncate(int len)
method dup (line 110) | ByteBuf dup()
method _ensureCapacity (line 118) | void _ensureCapacity(int required)
FILE: lib/network/util/byte_utils.dart
function viewOrSublist (line 3) | List<int> viewOrSublist(List<int> data, int offset, int length)
function readInt64 (line 11) | int readInt64(List<int> bytes, int offset)
function readInt32 (line 17) | int readInt32(List<int> bytes, int offset)
function readInt24 (line 24) | int readInt24(List<int> bytes, int offset)
function readInt16 (line 28) | int readInt16(List<int> bytes, int offset)
function setInt64 (line 32) | void setInt64(List<int> bytes, int offset, int value)
function setInt32 (line 37) | void setInt32(List<int> bytes, int offset, int value)
function setInt24 (line 44) | void setInt24(List<int> bytes, int offset, int value)
function setInt16 (line 50) | void setInt16(List<int> bytes, int offset, int value)
FILE: lib/network/util/cache.dart
class ExpiringCache (line 23) | class ExpiringCache<K, V> {
method set (line 30) | void set(K key, V value)
method putIfAbsent (line 38) | V? putIfAbsent(K key, V Function() ifAbsent)
method containsKey (line 47) | bool containsKey(K key)
method get (line 51) | V? get(K key)
method remove (line 57) | V? remove(K key)
method clear (line 63) | void clear()
class LruCache (line 72) | class LruCache<K, V> {
method get (line 78) | V? get(K key)
method pubIfAbsent (line 89) | V pubIfAbsent(K key, V Function() ifAbsent)
method set (line 99) | void set(K key, V value)
method remove (line 110) | void remove(K key)
method clear (line 116) | void clear()
FILE: lib/network/util/cert/basic_constraints.dart
class BasicConstraints (line 3) | class BasicConstraints {
FILE: lib/network/util/cert/cert_data.dart
class X509CertificateData (line 6) | class X509CertificateData {
class SubjectPublicKeyInfo (line 78) | class SubjectPublicKeyInfo {
class X509CertificateValidity (line 119) | class X509CertificateValidity {
class X509CertificateDataExtensions (line 132) | class X509CertificateDataExtensions {
class X509CertificatePublicKeyData (line 168) | class X509CertificatePublicKeyData {
method plainSha1FromJson (line 211) | Uint8List? plainSha1FromJson(List<int>? json)
method plainSha1ToJson (line 218) | List<int>? plainSha1ToJson(Uint8List? object)
class VmcData (line 239) | class VmcData {
method getFullSvgData (line 263) | String getFullSvgData()
FILE: lib/network/util/cert/der.dart
class DerValue (line 7) | class DerValue {
method toByteArray (line 38) | Uint8List toByteArray()
method encode (line 44) | void encode(DerOutputStream out)
method isConstructed (line 51) | bool isConstructed()
method isConstructedTag (line 55) | bool isConstructedTag(int constructedTag)
method getOctetString (line 62) | Uint8List getOctetString()
method getOID (line 77) | ASN1ObjectIdentifier getOID()
method toDerInputStream (line 96) | DerInputStream toDerInputStream()
method toString (line 101) | String toString()
class DerOutputStream (line 106) | class DerOutputStream {
method writeByte (line 109) | void writeByte(int byte)
method writeLength (line 113) | void writeLength(int length)
method writeBytes (line 125) | void writeBytes(Uint8List bytes)
method toByteArray (line 129) | Uint8List toByteArray()
class DerInputStream (line 134) | class DerInputStream {
method getLength (line 143) | int getLength(ByteBuf inStream)
method getInteger (line 156) | int getInteger()
method getSequence (line 164) | List<DerValue> getSequence(int startLen)
method getOID (line 185) | ASN1ObjectIdentifier getOID()
method getDerValue (line 193) | DerValue getDerValue()
method getOctetString (line 198) | Uint8List getOctetString()
class DerIndefLenConverter (line 208) | class DerIndefLenConverter {
method isEOC (line 219) | bool isEOC(Uint8List data, int pos)
method isLongForm (line 223) | bool isLongForm(int lengthByte)
method isIndefinite (line 227) | bool isIndefinite(int lengthByte)
method parseTag (line 231) | void parseTag()
method writeTag (line 258) | void writeTag()
method parseLength (line 269) | int parseLength()
method writeLengthAndValue (line 300) | void writeLengthAndValue()
method writeLength (line 327) | void writeLength(int curLen)
method getLengthBytes (line 351) | Uint8List getLengthBytes(int curLen)
method writeValue (line 385) | void writeValue(int curLen)
method convertBytes (line 391) | Uint8List? convertBytes(Uint8List indefData)
FILE: lib/network/util/cert/extension.dart
class Extension (line 4) | class Extension {
type ExtendedKeyUsage (line 25) | enum ExtendedKeyUsage {
FILE: lib/network/util/cert/key_usage.dart
type KeyUsage (line 5) | enum KeyUsage {
class ExtensionKeyUsage (line 34) | class ExtensionKeyUsage {
method keyUsageBytes (line 50) | Uint8List keyUsageBytes(int valueBytes)
FILE: lib/network/util/cert/pkcs12.dart
class Pkcs12 (line 11) | class Pkcs12 {
method generatePkcs12 (line 50) | Uint8List generatePkcs12(
method _generateLocalKeyId (line 211) | Uint8List _generateLocalKeyId()
method _generateSalt (line 215) | Uint8List _generateSalt()
method _generateHmac (line 219) | Uint8List _generateHmac(Uint8List bytesForHmac, Uint8List key, String ...
method formatPkcs12Password (line 228) | Uint8List formatPkcs12Password(Uint8List password)
method _generateSafeBagsForCerts (line 244) | _generateSafeBagsForCerts(List<String> certificates, Uint8List localKe...
method _generateSafeBagsForKey (line 267) | List<ASN1SafeBag> _generateSafeBagsForKey(String privateKey, Uint8List...
method _generateSafeBagsForShroudedKey (line 285) | _generateSafeBagsForShroudedKey(ASN1Object bagValue, Uint8List localKe...
method _getPrivateKeyInfoFromPem (line 301) | ASN1PrivateKeyInfo _getPrivateKeyInfoFromPem(String pem)
method _encryptRc2 (line 317) | Uint8List _encryptRc2(Uint8List bytesToEncrypt, ParametersWithIV gener...
method _decryptRc2 (line 321) | Uint8List _decryptRc2(Uint8List bytesToDecrypt, ParametersWithIV gener...
method _processRc2 (line 325) | Uint8List _processRc2(Uint8List bytes, ParametersWithIV generateDerive...
method _encrypt3des (line 340) | Uint8List _encrypt3des(Uint8List bytesToEncrypt, ParametersWithIV gene...
method _decrypt3des (line 344) | Uint8List _decrypt3des(Uint8List bytesToDecrypt, ParametersWithIV gene...
method _process3des (line 348) | Uint8List _process3des(Uint8List bytes, ParametersWithIV generateDeriv...
method _encryptRc4 (line 372) | Uint8List _encryptRc4(Uint8List bytesToEncrypt, KeyParameter generateD...
method _decryptRc4 (line 376) | Uint8List _decryptRc4(Uint8List bytesToDecrypt, KeyParameter generateD...
method _processRc4 (line 380) | Uint8List _processRc4(Uint8List bytesToEncrypt, KeyParameter generateD...
method _encrypt (line 390) | Uint8List _encrypt(
method _decrypt (line 437) | Uint8List _decrypt(Uint8List toDecrypt, String algorithm, Uint8List pw...
method _algorithmIdentifierFromDigest (line 484) | ASN1AlgorithmIdentifier _algorithmIdentifierFromDigest(String digestAl...
method _oiFromAlgorithm (line 501) | ASN1ObjectIdentifier _oiFromAlgorithm(String keyPbe)
method parsePkcs12 (line 551) | List<String> parsePkcs12(
method loadSafeContents (line 656) | void loadSafeContents(DerInputStream stream, List<String> pems, Uint8L...
method _parseSafaBag (line 671) | void _parseSafaBag(
method _decryptData (line 718) | Uint8List _decryptData(
method _algorithmFromOi (line 729) | String _algorithmFromOi(String keyPbe)
method _getDigestAlgorithmFromEncryptionAlgorithm (line 748) | String _getDigestAlgorithmFromEncryptionAlgorithm(String keyPbe)
method _getSaltFromAlgorithmParameters (line 762) | Uint8List _getSaltFromAlgorithmParameters(ASN1Object? parameters)
method _getMacIterFromAlgorithmParameters (line 771) | int _getMacIterFromAlgorithmParameters(ASN1Object? parameters)
FILE: lib/network/util/cert/x509.dart
class X509Utils (line 20) | class X509Utils {
method getSubjectHashName (line 33) | String getSubjectHashName(Map<String, String?> subject)
method encodeASN1ObjectToPem (line 54) | String encodeASN1ObjectToPem(ASN1Object asn1Object, String begin, Stri...
method crlDerToPem (line 64) | String crlDerToPem(Uint8List bytes)
method formatKeyString (line 75) | String formatKeyString(String key, String begin, String end,
method x509CertificateFromPem (line 99) | X509CertificateData x509CertificateFromPem(String pem)
method generateSelfSignedCertificate (line 128) | String generateSelfSignedCertificate(
method _x509FromAsn1Sequence (line 251) | X509CertificateData _x509FromAsn1Sequence(ASN1Sequence topLevelSeq)
method _getExtensionsFromSeq (line 331) | X509CertificateDataExtensions _getExtensionsFromSeq(ASN1Sequence extSe...
method keyUsageSequence (line 390) | ASN1Sequence? keyUsageSequence(ExtensionKeyUsage keyUsages)
method extendedKeyUsageEncodings (line 403) | ASN1Sequence? extendedKeyUsageEncodings(List<ExtendedKeyUsage>? extKey...
method _getSubjectPublicKeyInfoFromSeq (line 445) | SubjectPublicKeyInfo _getSubjectPublicKeyInfoFromSeq(ASN1Sequence pubK...
method _bytesAsString (line 503) | String _bytesAsString(Uint8List bytes)
method _fetchVmcLogo (line 519) | VmcData _fetchVmcLogo(ASN1Object extData)
method _fetchKeyUsageFromExtension (line 564) | List<KeyUsage> _fetchKeyUsageFromExtension(ASN1Object extData)
method _getBitOfByte (line 595) | bool _getBitOfByte(int byte, int bitIndex)
method _fetchExtendedKeyUsageFromExtension (line 608) | List<ExtendedKeyUsage> _fetchExtendedKeyUsageFromExtension(ASN1Object ...
method _fetchBasicConstraintsFromExtension (line 651) | List<dynamic> _fetchBasicConstraintsFromExtension(ASN1Object extData)
method _fetchSansFromExtension (line 670) | List<String> _fetchSansFromExtension(ASN1Object extData)
method _fetchCrlDistributionPoints (line 726) | List<String> _fetchCrlDistributionPoints(ASN1Object extData)
method _getValidityFromSeq (line 745) | X509CertificateValidity _getValidityFromSeq(ASN1Sequence validitySeque...
method _getDnFromSeq (line 769) | Map<String, String> _getDnFromSeq(ASN1Sequence issuerSequence)
method _identifier (line 793) | ASN1Set _identifier(String k, String value)
method _rsaSign (line 813) | Uint8List _rsaSign(Uint8List inBytes, RSAPrivateKey privateKey, String...
method _makePublicKeyBlock (line 825) | ASN1Sequence _makePublicKeyBlock(RSAPublicKey publicKey)
method _getDigestFromOi (line 843) | String _getDigestFromOi(String oi)
FILE: lib/network/util/compress.dart
function gzipDecode (line 9) | List<int> gzipDecode(List<int> byteBuffer)
function gzipEncode (line 20) | List<int> gzipEncode(List<int> input)
function brDecode (line 25) | List<int> brDecode(List<int> byteBuffer)
function zstdDecode (line 35) | Future<List<int>?> zstdDecode(List<int> byteBuffer)
function zlibDecode (line 47) | List<int> zlibDecode(List<int> byteBuffer)
FILE: lib/network/util/crts.dart
function main (line 38) | Future<void> main()
type StartState (line 42) | enum StartState { uninitialized, initializing, initialized }
class CertificateManager (line 44) | class CertificateManager {
method get (line 62) | SecurityContext? get(String host)
method cleanCache (line 69) | void cleanCache()
method getCertificateContext (line 74) | Future<SecurityContext> getCertificateContext(String host)
method generateLeafCertificatePem (line 99) | Future<String> generateLeafCertificatePem(String host)
method generate (line 107) | String generate(X509CertificateData caRoot, RSAPublicKey serverPubKey,...
method systemCertificateName (line 125) | Future<String> systemCertificateName()
method generateNewRootCA (line 135) | Future<void> generateNewRootCA()
method resetDefaultRootCA (line 181) | Future<void> resetDefaultRootCA()
method initCAConfig (line 192) | Future<void> initCAConfig()
method certificateFile (line 228) | Future<File> certificateFile()
method certificatePem (line 240) | Future<String> certificatePem()
method privateKeyFile (line 246) | Future<File> privateKeyFile()
method generatePkcs12 (line 258) | Future<Uint8List> generatePkcs12(String? password)
method importPkcs12 (line 265) | Future<void> importPkcs12(Uint8List pkcs12, String? password)
method getCertificateDetails (line 283) | Future<X509CertificateData> getCertificateDetails()
FILE: lib/network/util/crypto.dart
class CryptoUtils (line 21) | class CryptoUtils {
method getHash (line 50) | String getHash(Uint8List bytes, {String algorithmName = 'SHA-256'})
method getHashPlain (line 78) | Uint8List getHashPlain(Uint8List bytes, {String algorithmName = 'SHA-2...
method getPrivateKeyType (line 115) | String getPrivateKeyType(String pem)
method generateRSAKeyPair (line 137) | AsymmetricKeyPair generateRSAKeyPair({int keySize = 2048})
method rsaPublicKeyFromPem (line 152) | RSAPublicKey rsaPublicKeyFromPem(String pem)
method rsaPublicKeyFromDERBytes (line 160) | RSAPublicKey rsaPublicKeyFromDERBytes(Uint8List bytes)
method rsaPrivateKeyFromPem (line 183) | RSAPrivateKey rsaPrivateKeyFromPem(String pem)
method getBytesFromPEMString (line 196) | Uint8List getBytesFromPEMString(String pem, {bool checkHeader = true})
method rsaPrivateKeyFromDERBytes (line 215) | RSAPrivateKey rsaPrivateKeyFromDERBytes(Uint8List bytes)
method encodeRSAPublicKeyToPem (line 242) | String encodeRSAPublicKeyToPem(RSAPublicKey publicKey)
method encodeRSAPrivateKeyToPemPkcs1 (line 281) | String encodeRSAPrivateKeyToPemPkcs1(RSAPrivateKey rsaPrivateKey)
method encodeRSAPrivateKeyToPem (line 323) | String encodeRSAPrivateKeyToPem(RSAPrivateKey rsaPrivateKey)
method getSecureRandom (line 369) | SecureRandom getSecureRandom()
method removePKCS7Padding (line 380) | Uint8List removePKCS7Padding(Uint8List padded)
method addPKCS7Padding (line 386) | Uint8List addPKCS7Padding(Uint8List bytes, int blockSizeBytes)
FILE: lib/network/util/file_read.dart
class FileRead (line 7) | class FileRead {
method homeDir (line 10) | Future<File> homeDir()
method readAsString (line 24) | Future<String> readAsString(String file)
method read (line 29) | Future<Uint8List> read(String file)
method readFile (line 47) | Future<Uint8List> readFile(String path)
FILE: lib/network/util/lang.dart
function getFirstElement (line 3) | dynamic getFirstElement(List? list)
class Lists (line 9) | class Lists {
method isNotEmpty (line 10) | bool isNotEmpty(List? list)
method getElementType (line 14) | Type getElementType(dynamic list)
method convertList (line 25) | List<T> convertList<T>(List list)
class Strings (line 30) | class Strings {
method chunk (line 34) | List<String> chunk(String s, int chunkSize)
method isNotEmpty (line 43) | bool isNotEmpty(String? s)
class HexUtils (line 48) | class HexUtils {
method bytesToHex (line 49) | String bytesToHex(List<int> bytes)
method decode (line 53) | Uint8List decode(String hex)
FILE: lib/network/util/localizations.dart
class Localizations (line 6) | class Localizations {
FILE: lib/network/util/process_info.dart
function main (line 28) | void main()
class ProcessInfoUtils (line 37) | class ProcessInfoUtils {
method getProcessByPort (line 40) | Future<ProcessInfo?> getProcessByPort(InetSocketAddress socketAddress,...
method _getPid (line 70) | Future<int?> _getPid(InetSocketAddress socketAddress)
method getProcess (line 106) | Future<ProcessInfo?> getProcess(int pid)
class ProcessInfo (line 136) | class ProcessInfo {
method getIcon (line 158) | Future<Uint8List> getIcon()
method _getWindowsIcon (line 183) | Future<Uint8List?> _getWindowsIcon(String path)
method _getMacIcon (line 187) | Future<String> _getMacIcon(String path)
method toJson (line 198) | Map<String, dynamic> toJson()
method toString (line 203) | String toString()
FILE: lib/network/util/proxy_helper.dart
class ProxyHelper (line 34) | class ProxyHelper {
method localRequest (line 36) | localRequest(ChannelContext channelContext, HttpRequest msg, Channel c...
method crtDownload (line 66) | void crtDownload(ChannelContext channelContext, Channel channel, HttpR...
method exceptionHandler (line 86) | Future<void> exceptionHandler(
FILE: lib/network/util/random.dart
class RandomUtil (line 3) | class RandomUtil {
method randomString (line 6) | String randomString(int length)
FILE: lib/network/util/socket_address.dart
class InetSocketAddress (line 3) | class InetSocketAddress {
method toString (line 12) | String toString()
FILE: lib/network/util/system_proxy.dart
class SystemProxy (line 27) | class SystemProxy {
method getSystemProxy (line 66) | Future<ProxyInfo?> getSystemProxy(ProxyTypes types)
method setSystemProxy (line 71) | Future<void> setSystemProxy(int port, bool sslSetting, String proxyPas...
method setSslProxyEnable (line 76) | void setSslProxyEnable(bool proxyEnable, port)
method setSystemProxyEnable (line 82) | Future<void> setSystemProxyEnable(int port, bool enable, bool sslSetting,
method setProxyPassDomains (line 94) | Future<void> setProxyPassDomains(String proxyPassDomains)
method _getSystemProxy (line 101) | Future<ProxyInfo?> _getSystemProxy(ProxyTypes types)
method _setSystemProxy (line 106) | Future<void> _setSystemProxy(int port, bool sslSetting, String proxyPa...
method _setProxyEnable (line 113) | Future<void> _setProxyEnable(bool proxyEnable, bool sslSetting)
method _setSslProxyEnable (line 119) | Future<bool> _setSslProxyEnable(bool proxyEnable, int port)
method _setProxyPassDomains (line 124) | Future<void> _setProxyPassDomains(String proxyPassDomains)
class MacSystemProxy (line 127) | class MacSystemProxy implements SystemProxy {
method _shellQuote (line 131) | String _shellQuote(String s)
method _getSystemProxy (line 138) | Future<ProxyInfo?> _getSystemProxy(ProxyTypes proxyTypes)
method _setSystemProxy (line 184) | Future<bool> _setSystemProxy(int port, bool sslSetting, String proxyPa...
method _setSslProxyEnable (line 211) | Future<bool> _setSslProxyEnable(bool proxyEnable, port)
method hardwarePort (line 235) | Future<String> hardwarePort()
method _setProxyPassDomains (line 250) | Future<void> _setProxyPassDomains(String proxyPassDomains)
method _setProxyEnable (line 264) | Future<void> _setProxyEnable(bool proxyEnable, bool sslSetting)
method setProxyWithAuth (line 286) | Future<bool> setProxyWithAuth(List<String> commands)
method _concatCommands (line 302) | String _concatCommands(List<String> commands)
class WindowsSystemProxy (line 307) | class WindowsSystemProxy extends SystemProxy {
method _setProxyEnable (line 310) | Future<void> _setProxyEnable(bool proxyEnable, bool sslSetting)
method _getSystemProxy (line 316) | Future<ProxyInfo?> _getSystemProxy(ProxyTypes types)
method _setProxyPassDomains (line 349) | Future<void> _setProxyPassDomains(String proxyPassDomains)
method _internetSettings (line 354) | Future<String> _internetSettings(String cmd, List<String> args)
class LinuxSystemProxy (line 364) | class LinuxSystemProxy extends SystemProxy {
method _setSystemProxy (line 366) | Future<void> _setSystemProxy(int port, bool sslSetting, String proxyPa...
method _getSystemProxy (line 377) | Future<ProxyInfo?> _getSystemProxy(ProxyTypes types)
function main (line 399) | void main()
FILE: lib/network/util/task_queue.dart
class SequentialTaskQueue (line 4) | class SequentialTaskQueue {
method add (line 15) | void add(int id, int? dependency, Future Function() task,
method runTask (line 41) | Future<void> runTask(_Task task)
method waitForAll (line 65) | Future<void> waitForAll()
method cancel (line 73) | void cancel()
method reset (line 78) | void reset()
class _Task (line 84) | class _Task {
FILE: lib/network/util/tls.dart
class TLS (line 19) | class TLS {
method supportProtocols (line 21) | List<String>? supportProtocols(Uint8List data)
method isTLSClientHello (line 77) | bool isTLSClientHello(Uint8List data)
method getDomain (line 87) | String? getDomain(Uint8List data)
FILE: lib/network/util/uri.dart
class UriBuild (line 4) | class UriBuild {
method build (line 6) | Uri build(String url, {Map<String, String>? params})
class UriUtils (line 19) | class UriUtils {
method mapToQuery (line 21) | String mapToQuery(Map? map)
FILE: lib/storage/favorites.dart
class FavoriteStorage (line 28) | class FavoriteStorage {
method addFavorite (line 61) | Future<void> addFavorite(HttpRequest request)
method _snapshotFavorite (line 76) | Favorite _snapshotFavorite(HttpRequest request)
method removeFavorite (line 82) | Future<void> removeFavorite(Favorite favorite)
method flushConfig (line 89) | Future<void> flushConfig()
method toJson (line 94) | String toJson(Queue<Favorite> list)
method exportToFile (line 99) | Future<void> exportToFile(String path)
method exportToHarFile (line 106) | Future<void> exportToHarFile(String path, {String title = 'Favorites'})
method importFromFile (line 113) | Future<void> importFromFile(String path)
method trimFavoriteMessages (line 153) | bool trimFavoriteMessages(Favorite favorite)
class _FrameRef (line 196) | class _FrameRef {
class Favorite (line 203) | class Favorite {
method toJson (line 219) | Map<String, dynamic> toJson()
FILE: lib/storage/histories.dart
class HistoryStorage (line 35) | class HistoryStorage {
method _init (line 54) | Future<void> _init()
method _homePath (line 71) | Future<String> _homePath()
method openFile (line 86) | Future<File> openFile(String name)
method addHistory (line 93) | HistoryItem addHistory(String name, File file, int requestLength)
method getIndex (line 100) | int getIndex(HistoryItem item)
method updateHistory (line 105) | Future<void> updateHistory(int index, HistoryItem item)
method getHistory (line 111) | HistoryItem getHistory(int index)
method refresh (line 115) | Future<void> refresh()
method removeHistory (line 120) | Future<void> removeHistory(int index)
method getRequests (line 130) | Future<List<HttpRequest>> getRequests(HistoryItem history)
method flushRequests (line 144) | Future<void> flushRequests(HistoryItem history, List<HttpRequest> requ...
method addHarFile (line 161) | Future<HistoryItem> addHarFile(XFile file)
class HistoryTask (line 186) | class HistoryTask extends ListenerListEvent<HttpRequest> {
method ensureInstance (line 207) | HistoryTask ensureInstance(Configuration configuration, ListenableList...
method cleanHistory (line 212) | Future<void> cleanHistory()
method onAdd (line 228) | void onAdd(HttpRequest item)
method onRemove (line 237) | void onRemove(HttpRequest item)
method onBatchRemove (line 240) | void onBatchRemove(List<HttpRequest> items)
method resetList (line 245) | Future<void> resetList()
method cancelTask (line 258) | void cancelTask()
method startTask (line 269) | Future<void> startTask()
method writeTask (line 286) | Future<void> writeTask()
class HistoryItem (line 311) | class HistoryItem {
method toJson (line 330) | Map<String, dynamic> toJson()
method toString (line 355) | String toString()
FILE: lib/storage/local_storage.dart
class LocalStorage (line 3) | class LocalStorage {
method getBool (line 4) | Future<bool?> getBool(String key, {bool? defaultValue})
method setBool (line 9) | Future<void> setBool(String key, bool value)
FILE: lib/storage/path.dart
class Paths (line 5) | class Paths {
method getPath (line 9) | Future<File> getPath(String fileName)
method createFile (line 24) | Future<File> createFile(String dir, String filename)
FILE: lib/storage/shared_preference_keys.dart
class SharedPreferenceKeys (line 3) | class SharedPreferenceKeys {
FILE: lib/ui/app_update/app_update_repository.dart
class AppUpdateRepository (line 16) | class AppUpdateRepository {
method checkUpdate (line 19) | Future<void> checkUpdate(BuildContext context, {bool canIgnore = true,...
method getLatestVersion (line 65) | Future<RemoteVersionEntity?> getLatestVersion({bool includePreReleases...
method compareVersions (line 85) | bool compareVersions(String currentVersion, String latestVersion)
method normalizeVersion (line 86) | String normalizeVersion(String version)
method parseVersion (line 90) | List<int> parseVersion(String version)
FILE: lib/ui/app_update/constants.dart
class Constants (line 1) | abstract class Constants {
FILE: lib/ui/app_update/new_version_dialog.dart
class NewVersionDialog (line 10) | class NewVersionDialog extends StatelessWidget {
method show (line 23) | Future<void> show(BuildContext context)
method build (line 36) | Widget build(BuildContext context)
FILE: lib/ui/app_update/remote_version_entity.dart
class RemoteVersionEntity (line 3) | class RemoteVersionEntity {
method toString (line 23) | String toString()
class GithubReleaseParser (line 28) | abstract class GithubReleaseParser {
method parse (line 29) | RemoteVersionEntity parse(Map<String, dynamic> json)
FILE: lib/ui/component/app_dialog.dart
class AppAlertDialog (line 4) | class AppAlertDialog extends StatelessWidget {
method show (line 19) | Future<void> show(BuildContext context)
method build (line 28) | Widget build(BuildContext context)
type AlertType (line 51) | enum AlertType {
class CustomToast (line 63) | class CustomToast extends StatelessWidget {
method build (line 92) | Widget build(BuildContext context)
method show (line 108) | void show(BuildContext context, {Alignment alignment = Alignment.botto...
FILE: lib/ui/component/buttons.dart
class Buttons (line 3) | class Buttons {
FILE: lib/ui/component/chinese_font.dart
class SystemChineseFont (line 3) | class SystemChineseFont {
function useSystemChineseFont (line 37) | TextStyle useSystemChineseFont()
function useSystemChineseFont (line 53) | TextTheme useSystemChineseFont()
function useSystemChineseFont (line 60) | ThemeData useSystemChineseFont()
FILE: lib/ui/component/context_menu_region.dart
type ContextMenuBuilder (line 4) | typedef ContextMenuBuilder = List<ContextMenuButtonItem> Function();
class ContextMenuRegion (line 8) | class ContextMenuRegion extends StatefulWidget {
method createState (line 22) | State<ContextMenuRegion> createState()
class _ContextMenuRegionState (line 25) | class _ContextMenuRegionState extends State<ContextMenuRegion> {
method _onSecondaryTapUp (line 43) | void _onSecondaryTapUp(TapUpDetails details)
method _onTap (line 47) | void _onTap()
method _onLongPressStart (line 54) | void _onLongPressStart(LongPressStartDetails details)
method _onLongPress (line 58) | void _onLongPress()
method _show (line 64) | void _show(Offset position)
method _hide (line 75) | void _hide()
method dispose (line 80) | void dispose()
method build (line 86) | Widget build(BuildContext context)
FILE: lib/ui/component/device.dart
class DeviceUtils (line 6) | class DeviceUtils {
method deviceId (line 8) | Future<String?> deviceId()
method desktopDeviceId (line 20) | Future<String?> desktopDeviceId()
FILE: lib/ui/component/history_cache_time.dart
class HistoryCacheTime (line 7) | class HistoryCacheTime extends StatefulWidget {
method createState (line 14) | State<StatefulWidget> createState()
class _HistoryCacheTimeState (line 17) | class _HistoryCacheTimeState extends State<HistoryCacheTime> {
method build (line 21) | Widget build(BuildContext context)
FILE: lib/ui/component/http_method_popup.dart
class MethodPopupMenu (line 6) | class MethodPopupMenu extends StatelessWidget {
method _methodColor (line 13) | Color _methodColor(HttpMethod? m, BuildContext context)
method build (line 41) | Widget build(BuildContext context)
method _buildMenuItem (line 74) | Widget _buildMenuItem(HttpMethod? m, BuildContext context)
FILE: lib/ui/component/json/json_text.dart
class JsonText (line 28) | class JsonText extends StatefulWidget {
method createState (line 45) | State<JsonText> createState()
class _JsonTextState (line 48) | class _JsonTextState extends State<JsonText> {
method initState (line 54) | void initState()
method dispose (line 60) | void dispose()
method build (line 67) | Widget build(BuildContext context)
method jsonTextWidget (line 79) | Widget jsonTextWidget(BuildContext context)
method scrollToMatch (line 117) | Future<void> scrollToMatch(JsonParser jsonParser, [List<List<TextSpan>...
method _ensureVisibleCenter (line 155) | Future<void> _ensureVisibleCenter(GlobalKey key, Duration duration)
method _findChunkIndexForKey (line 163) | int _findChunkIndexForKey(List<List<TextSpan>> chunks, GlobalKey key)
method _textSpanContainsKey (line 173) | bool _textSpanContainsKey(TextSpan span, GlobalKey key)
method splitTextSpans (line 188) | List<List<TextSpan>> splitTextSpans(List<TextSpan> spans, int chunkSize)
method endsWithNewline (line 195) | bool endsWithNewline(TextSpan s)
method startsWithNewline (line 196) | bool startsWithNewline(TextSpan s)
method trackingScroll (line 225) | ScrollController trackingScroll()
class JsonParser (line 259) | class JsonParser {
method getLength (line 269) | int getLength()
method getJsonTree (line 279) | List<TextSpan> getJsonTree()
method getMapText (line 296) | List<TextSpan> getMapText(Map<String, dynamic> map,
method getArrayText (line 325) | List<TextSpan> getArrayText(List<dynamic> list, {String openPrefix = '...
method getBasicValue (line 348) | TextSpan getBasicValue(dynamic value, String suffix, {String? prefix})
method _highlightMatches (line 380) | List<InlineSpan> _highlightMatches(String text, {Color? textColor})
FILE: lib/ui/component/json/json_viewer.dart
class JsonViewer (line 29) | class JsonViewer extends StatelessWidget {
method build (line 37) | Widget build(BuildContext context)
method getContentWidget (line 60) | Widget getContentWidget(dynamic content,
method scrollToMatch (line 79) | void scrollToMatch(List<GlobalKey> matchKeys)
class JsonObjectViewer (line 97) | class JsonObjectViewer extends StatefulWidget {
method createState (line 114) | JsonObjectViewerState createState()
class JsonObjectViewerState (line 117) | class JsonObjectViewerState extends State<JsonObjectViewer> {
method didUpdateWidget (line 121) | void didUpdateWidget(covariant JsonObjectViewer oldWidget)
method build (line 127) | Widget build(BuildContext context)
method _getList (line 137) | List<Widget> _getList()
method getKeyWidget (line 171) | Widget getKeyWidget(MapEntry entry)
method getContentWidget (line 210) | Widget getContentWidget(dynamic content, ColorTheme colorTheme,
class JsonArrayViewer (line 232) | class JsonArrayViewer extends StatefulWidget {
method createState (line 249) | State<JsonArrayViewer> createState()
class _JsonArrayViewerState (line 252) | class _JsonArrayViewerState extends State<JsonArrayViewer> {
method build (line 256) | Widget build(BuildContext context)
method initState (line 266) | void initState()
method _getList (line 271) | List<Widget> _getList()
method getKeyWidget (line 303) | Widget getKeyWidget(dynamic content, int index)
function _getValueWidget (line 331) | Widget _getValueWidget(dynamic value, ColorTheme colorTheme,
function _highlightText (line 377) | List<InlineSpan> _highlightText(String text, TextStyle textStyle,
function _getTypeName (line 427) | String _getTypeName(dynamic content)
function _copyValue (line 443) | Widget _copyValue(BuildContext context, Widget child, Object? value)
function showJsonCopyMenu (line 452) | void showJsonCopyMenu(BuildContext context, Offset position, Object? value)
function _isExtensible (line 474) | bool _isExtensible(dynamic content)
FILE: lib/ui/component/json/theme.dart
class ColorTheme (line 3) | class ColorTheme {
method light (line 4) | ColorTheme light(ColorScheme colorScheme)
method dark (line 15) | ColorTheme dark(ColorScheme colorScheme)
method of (line 46) | ColorTheme of(BuildContext context)
FILE: lib/ui/component/json/toast.dart
class Toast (line 4) | class Toast {
method show (line 5) | void show(String message, BuildContext context)
FILE: lib/ui/component/memory_cleanup.dart
class MemoryCleanupMonitor (line 25) | class MemoryCleanupMonitor {
method onMonitor (line 28) | void onMonitor({Function? onCleanup})
method _cleanup (line 42) | void _cleanup(int threshold, Function? onCleanup)
FILE: lib/ui/component/model/search_model.dart
class SearchModel (line 22) | class SearchModel {
method clone (line 70) | SearchModel clone()
method toString (line 86) | String toString()
method filter (line 91) | bool filter(HttpRequest request, HttpResponse? response)
method _matchProtocol (line 156) | bool _matchProtocol(Protocol p, HttpRequest request, HttpResponse? res...
method keywordFilter (line 172) | bool keywordFilter(String keyword, bool caseSensitive, Option option, ...
type Option (line 216) | enum Option {
type Protocol (line 227) | enum Protocol { http, https, ws, http1, h2 }
FILE: lib/ui/component/multi_window.dart
function multiWindow (line 62) | Widget multiWindow(int windowId, Map<dynamic, dynamic> argument)
type Operation (line 165) | enum Operation {
class MultiWindow (line 177) | class MultiWindow {
method invokeRefreshRewrite (line 181) | Future<void> invokeRefreshRewrite(Operation operation,
method openWindow (line 192) | Future<WindowController> openWindow(String title, String widgetName,
method _handleRefreshRewrite (line 218) | Future<void> _handleRefreshRewrite(Operation operation, Map<dynamic, d...
function registerMethodHandler (line 257) | void registerMethodHandler()
function encodeWindow (line 356) | Future<void> encodeWindow(EncoderType type, BuildContext context, [Strin...
function openScriptConsoleWindow (line 377) | Future<void> openScriptConsoleWindow()
FILE: lib/ui/component/proxy_port_setting.dart
class PortWidget (line 7) | class PortWidget extends StatefulWidget {
method createState (line 15) | State<StatefulWidget> createState()
class _PortState (line 20) | class _PortState extends State<PortWidget> {
method initState (line 27) | void initState()
method dispose (line 52) | void dispose()
method build (line 59) | Widget build(BuildContext context)
FILE: lib/ui/component/qrcode/qr_scan_view.dart
class QrCodeScanner (line 10) | class QrCodeScanner {
method scan (line 11) | Future<String?> scan(BuildContext context)
class QeCodeScanView (line 55) | class QeCodeScanView extends StatefulWidget {
method createState (line 59) | State<StatefulWidget> createState()
class _QrReaderViewState (line 64) | class _QrReaderViewState extends State<QeCodeScanView> with TickerProvid...
method dispose (line 75) | void dispose()
method _onCreateController (line 80) | void _onCreateController(QrReaderViewController controller)
method startScan (line 85) | void startScan()
method _initAnimation (line 102) | void _initAnimation()
method stop (line 126) | void stop()
method _upState (line 141) | void _upState()
method build (line 163) | Widget build(BuildContext context)
class QrScanBoxPainter (line 232) | class QrScanBoxPainter extends CustomPainter {
method paint (line 240) | void paint(Canvas canvas, Size size)
method shouldRepaint (line 294) | bool shouldRepaint(QrScanBoxPainter oldDelegate)
method shouldRebuildSemantics (line 297) | bool shouldRebuildSemantics(QrScanBoxPainter oldDelegate)
FILE: lib/ui/component/search/highlight_text.dart
class HighlightTextWidget (line 4) | class HighlightTextWidget extends StatelessWidget {
method build (line 14) | Widget build(BuildContext context)
method _highlightMatches (line 28) | List<InlineSpan> _highlightMatches(BuildContext context)
method _scrollToMatch (line 79) | void _scrollToMatch(BuildContext context, List<GlobalKey> matchKeys)
FILE: lib/ui/component/search/search_controller.dart
class SearchTextController (line 8) | class SearchTextController extends ValueNotifier<SearchSettings> with Wi...
method shouldSearch (line 22) | bool shouldSearch()
method toggleCaseSensitivity (line 26) | void toggleCaseSensitivity()
method toggleIsRegExp (line 30) | void toggleIsRegExp()
method _onPatternControllerChanged (line 34) | void _onPatternControllerChanged()
method updateMatchCount (line 42) | void updateMatchCount(int count)
method movePrevious (line 49) | void movePrevious()
method moveNext (line 59) | void moveNext()
method closeSearch (line 69) | void closeSearch()
method updateOverlayPosition (line 73) | void updateOverlayPosition(double top, double right)
method didChangeMetrics (line 82) | void didChangeMetrics()
method dispose (line 105) | void dispose()
method showSearchOverlay (line 118) | void showSearchOverlay(BuildContext context, {double? top, double? rig...
method removeSearchOverlay (line 127) | void removeSearchOverlay()
method _buildSearchOverlay (line 132) | OverlayEntry _buildSearchOverlay(BuildContext context, {double? top, d...
class SearchSettings (line 152) | class SearchSettings {
method copyWith (line 171) | SearchSettings copyWith({
FILE: lib/ui/component/search/search_field.dart
class SearchField (line 11) | class SearchField extends StatefulWidget {
method createState (line 20) | State<SearchField> createState()
class _SearchFieldState (line 23) | class _SearchFieldState extends State<SearchField> {
method build (line 45) | Widget build(BuildContext context)
method _getText (line 129) | Text _getText()
FILE: lib/ui/component/search_condition.dart
class SearchConditions (line 28) | class SearchConditions extends StatefulWidget {
method createState (line 36) | State<StatefulWidget> createState()
class SearchConditionsState (line 41) | class SearchConditionsState extends State<SearchConditions> {
method initState (line 62) | void initState()
method build (line 68) | Widget build(BuildContext context)
method protocolsWidget (line 226) | Widget protocolsWidget()
method options (line 301) | Widget options(String title, Option option)
method row (line 318) | Widget row(Widget child, Widget child2)
method textField (line 325) | Widget textField({String? initialValue, final ValueChanged<String>? on...
class DropdownMenu (line 345) | class DropdownMenu<T> extends StatefulWidget {
method createState (line 353) | State<StatefulWidget> createState()
class DropdownMenuState (line 358) | class DropdownMenuState extends State<DropdownMenu> {
method initState (line 362) | void initState()
method build (line 368) | Widget build(BuildContext context)
FILE: lib/ui/component/split_view.dart
class VerticalSplitView (line 3) | class VerticalSplitView extends StatefulWidget {
method createState (line 22) | State<VerticalSplitView> createState()
class _VerticalSplitViewState (line 25) | class _VerticalSplitViewState extends State<VerticalSplitView> {
method initState (line 37) | void initState()
method build (line 43) | Widget build(BuildContext context)
FILE: lib/ui/component/state_component.dart
class KeepAliveWrapper (line 3) | class KeepAliveWrapper extends StatefulWidget {
method createState (line 9) | State<KeepAliveWrapper> createState()
class _KeepAliveWrapperState (line 12) | class _KeepAliveWrapperState extends State<KeepAliveWrapper> with Automa...
method build (line 14) | Widget build(BuildContext context)
method didUpdateWidget (line 20) | void didUpdateWidget(covariant KeepAliveWrapper oldWidget)
FILE: lib/ui/component/text_field.dart
class HighlightTextEditingController (line 21) | class HighlightTextEditingController extends TextEditingController {
method highlight (line 30) | bool highlight(String? value, {bool caseSensitive = true})
method buildTextSpan (line 36) | TextSpan buildTextSpan({required BuildContext context, TextStyle? styl...
function decoration (line 75) | InputDecoration decoration(BuildContext context, {String? label, String?...
FILE: lib/ui/component/transition.dart
class ColorTransition (line 4) | class ColorTransition extends StatefulWidget {
method createState (line 20) | State<ColorTransition> createState()
class ColorTransitionState (line 25) | class ColorTransitionState extends State<ColorTransition> with SingleTic...
method initState (line 30) | void initState()
method dispose (line 63) | void dispose()
method build (line 69) | Widget build(BuildContext context)
FILE: lib/ui/component/utils.dart
function getIcon (line 42) | Widget getIcon(HttpResponse? response, {Color? color})
function getPackagesSize (line 64) | String getPackagesSize(HttpRequest request, HttpResponse? response)
function getPackage (line 73) | String getPackage(int? size)
function copyRawRequest (line 87) | String copyRawRequest(HttpRequest request)
function copyRequest (line 101) | String copyRequest(HttpRequest request, HttpResponse? response)
function menuPosition (line 118) | RelativeRect menuPosition(BuildContext context)
function contextMenu (line 132) | Widget contextMenu(BuildContext context, EditableTextState editableTextS...
function unSelect (line 183) | void unSelect(EditableTextState editableTextState)
function futureWidget (line 192) | Widget futureWidget<T>(Future<T> future, Widget Function(T data) toWidge...
function showContextMenu (line 213) | Future showContextMenu(BuildContext context, Offset offset, {required Li...
function showConfirmDialog (line 225) | Future<T?> showConfirmDialog<T>(BuildContext context, {String? title, St...
function trackingScroll (line 252) | ScrollController? trackingScroll(ScrollController? scrollController)
FILE: lib/ui/component/widgets.dart
class CustomPopupMenuItem (line 4) | class CustomPopupMenuItem<T> extends PopupMenuItem<T> {
method createState (line 19) | PopupMenuItemState<T, CustomPopupMenuItem<T>> createState()
class _CustomPopupMenuItemState (line 22) | class _CustomPopupMenuItemState<T> extends PopupMenuItemState<T, CustomP...
method build (line 24) | Widget build(BuildContext context)
class PopupMenuContainer (line 34) | class PopupMenuContainer extends PopupMenuEntry {
method represents (line 43) | bool represents(value)
method createState (line 46) | State<StatefulWidget> createState()
class _PopupMenuContainerState (line 49) | class _PopupMenuContainerState extends State<PopupMenuContainer> {
method build (line 51) | Widget build(BuildContext context)
class SwitchWidget (line 56) | class SwitchWidget extends StatefulWidget {
method createState (line 67) | State<StatefulWidget> createState()
class _SwitchState (line 70) | class _SwitchState extends State<SwitchWidget> {
method build (line 72) | Widget build(BuildContext context)
class Dot (line 103) | class Dot extends StatelessWidget {
method build (line 110) | Widget build(BuildContext context)
class BottomSheetItem (line 119) | class BottomSheetItem extends StatelessWidget {
method build (line 126) | Widget build(BuildContext context)
class IconText (line 136) | class IconText extends StatelessWidget {
method build (line 146) | Widget build(BuildContext context)
class LazyIndexedStack (line 158) | class LazyIndexedStack extends StatefulWidget {
method createState (line 169) | State<LazyIndexedStack> createState()
class _LazyIndexedStackState (line 172) | class _LazyIndexedStackState extends State<LazyIndexedStack> {
method initState (line 176) | void initState()
method didUpdateWidget (line 182) | void didUpdateWidget(LazyIndexedStack oldWidget)
method build (line 190) | Widget build(BuildContext context)
FILE: lib/ui/configuration.dart
class ColorMapping (line 27) | class ColorMapping {
method getColor (line 41) | Color getColor(String colorName)
method getColorName (line 45) | String getColorName(Color color)
class ThemeModel (line 50) | class ThemeModel {
method copy (line 57) | ThemeModel copy({ThemeMode? mode, bool? useMaterial3})
class AppConfiguration (line 65) | class AppConfiguration {
method initConfig (line 182) | Future<void> initConfig()
method flushConfig (line 234) | Future<void> flushConfig()
method toJson (line 249) | Map<String, dynamic> toJson()
FILE: lib/ui/content/body.dart
class HttpBodyWidget (line 51) | class HttpBodyWidget extends StatefulWidget {
method createState (line 67) | State<StatefulWidget> createState()
class HttpBodyState (line 72) | class HttpBodyState extends State<HttpBodyWidget> {
method initState (line 83) | void initState()
method didUpdateWidget (line 93) | void didUpdateWidget(covariant HttpBodyWidget oldWidget)
method onKeyEvent (line 103) | bool onKeyEvent(KeyEvent event)
method _loadDecoded (line 114) | Future<void> _loadDecoded()
method dispose (line 122) | void dispose()
method build (line 130) | Widget build(BuildContext context)
method hideSearchOverlay (line 214) | void hideSearchOverlay()
method isJsonText (line 219) | bool isJsonText()
method titleWidget (line 227) | Widget titleWidget({bool inNewWindow = false})
method downloadImageButton (line 374) | Widget downloadImageButton()
method showRequestRewrite (line 408) | Future<void> showRequestRewrite()
method openNew (line 446) | void openNew()
class _Body (line 469) | class _Body extends StatefulWidget {
method createState (line 484) | State<StatefulWidget> createState()
class _BodyState (line 489) | class _BodyState extends State<_Body> {
method initState (line 494) | void initState()
method changeState (line 500) | void changeState(HttpMessage? message, ViewType viewType)
method build (line 508) | Widget build(BuildContext context)
method getBody (line 512) | Future<String?> getBody()
method _getBody (line 544) | Widget _getBody(ViewType type)
class Tabs (line 629) | class Tabs {
method of (line 632) | Tabs of(ContentType? contentType, bool isJsonText)
method tabList (line 664) | List<Tab> tabList()
type ViewType (line 669) | enum ViewType {
class HexViewer (line 696) | class HexViewer extends StatelessWidget {
method build (line 704) | Widget build(BuildContext context)
method _formatHex (line 712) | String _formatHex(Uint8List data, int bytesPerRow)
class _DecodedHttpMessage (line 749) | class _DecodedHttpMessage extends HttpMessage {
method toJson (line 759) | Map<String, dynamic> toJson()
FILE: lib/ui/content/headers.dart
class HeadersWidget (line 32) | class HeadersWidget extends StatefulWidget {
method createState (line 52) | State<HeadersWidget> createState()
class _HeadersWidgetState (line 55) | class _HeadersWidgetState extends State<HeadersWidget> {
method initState (line 64) | void initState()
method dispose (line 74) | void dispose()
method _buildHeaderModeToggle (line 79) | Widget _buildHeaderModeToggle(BuildContext context)
method setMode (line 84) | void setMode(bool text)
method build (line 100) | Widget build(BuildContext context)
method buildTextMode (line 126) | List<Widget> buildTextMode(HttpMessage? message)
method _buildHeaderRows (line 148) | List<Widget> _buildHeaderRows(HttpMessage? message)
method _buildRawHeaders (line 177) | String _buildRawHeaders(HttpMessage? message)
FILE: lib/ui/content/menu.dart
class ShareWidget (line 23) | class ShareWidget extends StatelessWidget {
method build (line 31) | Widget build(BuildContext context)
method _sharePositionOrigin (line 87) | Future<Rect?> _sharePositionOrigin(BuildContext context)
class DetailMenuWidget (line 96) | class DetailMenuWidget extends StatelessWidget {
method build (line 105) | Widget build(BuildContext context)
FILE: lib/ui/content/panel.dart
class NetworkTabController (line 35) | class NetworkTabController extends StatefulWidget {
method change (line 57) | void change(HttpRequest? request, HttpResponse? response)
method changeState (line 64) | void changeState()
method createState (line 70) | State<StatefulWidget> createState()
class NetworkTabState (line 77) | class NetworkTabState extends State<NetworkTabController> with SingleTic...
method changeState (line 91) | void changeState()
method initState (line 98) | void initState()
method dispose (line 116) | void dispose()
method onKeyEvent (line 122) | bool onKeyEvent(KeyEvent event)
method build (line 134) | Widget build(BuildContext context)
method request (line 190) | Widget request()
method response (line 210) | Widget response()
method message (line 224) | List<Widget> message(HttpMessage? message, String type, ScrollControll...
function expansionTile (line 235) | Widget expansionTile(String title, List<Widget> content,
class RequestParams (line 247) | class RequestParams extends StatelessWidget {
method build (line 255) | Widget build(BuildContext context)
class General (line 280) | class General extends StatelessWidget {
method build (line 288) | Widget build(BuildContext context)
class Cookies (line 333) | class Cookies extends StatelessWidget {
method build (line 341) | Widget build(BuildContext context)
method _cookieWidget (line 352) | Iterable<Widget>? _cookieWidget(String? cookie)
class RowWidget (line 364) | class RowWidget extends StatelessWidget {
method build (line 372) | Widget build(BuildContext context)
FILE: lib/ui/content/web_socket.dart
class Websocket (line 20) | class Websocket extends StatelessWidget {
method build (line 27) | Widget build(BuildContext context)
class _PreviewDialog (line 117) | class _PreviewDialog extends StatefulWidget {
method createState (line 123) | State<_PreviewDialog> createState()
class _PreviewDialogState (line 126) | class _PreviewDialogState extends State<_PreviewDialog> {
method build (line 130) | Widget build(BuildContext context)
method jsonText (line 184) | Widget jsonText()
method jsonView (line 200) | Widget jsonView()
method isJsonText (line 217) | bool isJsonText(List<int> bytes)
method formatHexDump (line 222) | String formatHexDump(List<int> bytes)
method safeTextPreview (line 237) | String safeTextPreview(List<int> bytes)
FILE: lib/ui/desktop/common.dart
function showRequestRewriteDialog (line 9) | Future<void> showRequestRewriteDialog(BuildContext context, HttpRequest ...
FILE: lib/ui/desktop/debug/breakpoint_executor.dart
class BreakpointExecutor (line 6) | class BreakpointExecutor extends StatefulWidget {
method createState (line 25) | State<BreakpointExecutor> createState()
class _BreakpointExecutorState (line 28) | class _BreakpointExecutorState extends State<BreakpointExecutor> {
method initState (line 33) | void initState()
method build (line 40) | Widget build(BuildContext context)
method _buildResponseBody (line 60) | Widget _buildResponseBody()
FILE: lib/ui/desktop/desktop.dart
class DesktopHomePage (line 46) | class DesktopHomePage extends StatefulWidget {
method createState (line 53) | State<DesktopHomePage> createState()
class _DesktopHomePagePageState (line 56) | class _DesktopHomePagePageState extends State<DesktopHomePage> implement...
method onRequest (line 69) | void onRequest(Channel channel, HttpRequest request)
method onResponse (line 79) | void onResponse(ChannelContext channelContext, HttpResponse response)
method onMessage (line 84) | void onMessage(Channel channel, HttpMessage message, WebSocketFrame fr...
method initState (line 91) | void initState()
method build (line 106) | Widget build(BuildContext context)
method showUpgradeNotice (line 153) | void showUpgradeNotice()
FILE: lib/ui/desktop/left_menus/favorite.dart
class Favorites (line 49) | class Favorites extends StatefulWidget {
method createState (line 55) | State<StatefulWidget> createState()
class _FavoritesState (line 60) | class _FavoritesState extends State<Favorites> {
method initState (line 64) | void initState()
method build (line 72) | Widget build(BuildContext context)
class _FavoriteItem (line 110) | class _FavoriteItem extends StatefulWidget {
method createState (line 119) | State<_FavoriteItem> createState()
class _FavoriteItemState (line 122) | class _FavoriteItemState extends State<_FavoriteItem> {
method build (line 131) | Widget build(BuildContext context)
method menu (line 169) | void menu(LongPressDownDetails details, HttpRequest request)
method showCustomRepeat (line 210) | Future<void> showCustomRepeat(HttpRequest request)
method onRepeat (line 221) | void onRepeat(HttpRequest request)
method popupItem (line 236) | PopupMenuItem popupItem(String text, {VoidCallback? onTap})
method rename (line 241) | void rename(Favorite item)
method requestEdit (line 270) | Future<void> requestEdit(HttpRequest request)
method onClick (line 288) | void onClick(HttpRequest request)
class _FavoritesActions (line 307) | class _FavoritesActions extends StatelessWidget {
method build (line 313) | Widget build(BuildContext context)
FILE: lib/ui/desktop/left_menus/history.dart
class HistoryPageWidget (line 43) | class HistoryPageWidget extends StatelessWidget {
method build (line 53) | Widget build(BuildContext context)
method requestListWidget (line 71) | Widget requestListWidget(BuildContext context, Map arguments)
class _HistoryListWidget (line 99) | class _HistoryListWidget extends StatefulWidget {
method createState (line 110) | State<StatefulWidget> createState()
class _HistoryListState (line 113) | class _HistoryListState extends State<_HistoryListWidget> {
method initState (line 127) | void initState()
method build (line 141) | Widget build(BuildContext context)
method import (line 194) | Future<void> import()
method buildSaveSession (line 216) | Widget buildSaveSession()
method buildItem (line 239) | Widget buildItem(BuildContext rootContext, int index, HistoryItem item)
method toRequestsView (line 284) | void toRequestsView(HistoryItem item)
method renameHistory (line 295) | void renameHistory(HistoryStorage storage, HistoryItem item)
method export (line 328) | Future<void> export(HistoryItem item)
method _repeatAllRequests (line 347) | void _repeatAllRequests(Iterable<HttpRequest> requests)
FILE: lib/ui/desktop/left_menus/navigation.dart
class LeftNavigationBar (line 26) | class LeftNavigationBar extends StatefulWidget {
method createState (line 35) | State<StatefulWidget> createState()
class _LeftNavigationBarState (line 40) | class _LeftNavigationBarState extends State<LeftNavigationBar> {
method build (line 63) | Widget build(BuildContext context)
method leftNavigation (line 113) | Widget leftNavigation(int index)
FILE: lib/ui/desktop/preference.dart
class Preference (line 26) | class Preference extends StatefulWidget {
method createState (line 33) | State<StatefulWidget> createState()
class _PreferenceState (line 36) | class _PreferenceState extends State<Preference> {
method initState (line 44) | void initState()
method dispose (line 54) | void dispose()
method build (line 60) | Widget build(BuildContext context)
method themeColor (line 158) | Widget themeColor(BuildContext context)
method memoryCleanup (line 184) | Widget memoryCleanup(BuildContext context, AppLocalizations localizati...
class DropdownMenuInputItem (line 236) | class DropdownMenuInputItem extends DropdownMenuItem<int> {
FILE: lib/ui/desktop/request/domians.dart
class DomainList (line 45) | class DomainList extends StatefulWidget {
method createState (line 62) | State<StatefulWidget> createState()
class DomainWidgetState (line 67) | class DomainWidgetState extends State<DomainList> with AutomaticKeepAliv...
method changeState (line 82) | void changeState()
method initState (line 94) | void initState()
method build (line 120) | Widget build(BuildContext context)
method search (line 138) | void search(SearchModel? val)
method searchFilter (line 145) | LinkedHashMap<String, DomainRequests> searchFilter(SearchModel searchM...
method getDomainRequests (line 192) | DomainRequests getDomainRequests(HttpRequest request)
method appIcon (line 212) | Widget? appIcon(HttpRequest request)
method addResponse (line 236) | void addResponse(ChannelContext channelContext, HttpResponse response)
method currentView (line 276) | List<HttpRequest> currentView()
class DomainRequests (line 297) | class DomainRequests extends StatefulWidget {
method addRequest (line 320) | void addRequest(String? requestId, HttpRequest request, bool sortDesc)
method getRequest (line 335) | RequestWidget? getRequest(HttpResponse response)
method search (line 359) | Iterable<RequestWidget> search(SearchModel searchModel)
method copy (line 365) | DomainRequests copy({Iterable<RequestWidget>? body, bool? selected})
method createState (line 390) | State<StatefulWidget> createState()
class _DomainRequestsState (line 395) | class _DomainRequestsState extends State<DomainRequests> {
method initState (line 405) | void initState()
method build (line 428) | Widget build(BuildContext context)
method _hostWidget (line 436) | Widget _hostWidget(String title)
method repeatDomainRequests (line 491) | void repeatDomainRequests()
method hostFilterMenu (line 505) | Menu hostFilterMenu()
class HostWidget (line 539) | class HostWidget extends StatelessWidget {
method build (line 546) | Widget build(BuildContext context)
FILE: lib/ui/desktop/request/list.dart
class DesktopRequestListWidget (line 41) | class DesktopRequestListWidget extends StatefulWidget {
method createState (line 49) | State<StatefulWidget> createState()
class DesktopRequestListState (line 54) | class DesktopRequestListState extends State<DesktopRequestListWidget> wi...
method initState (line 67) | void initState()
method dispose (line 78) | void dispose()
method build (line 83) | Widget build(BuildContext context)
method popupMenus (line 118) | Widget popupMenus()
method add (line 170) | void add(Channel channel, HttpRequest request)
method addResponse (line 177) | void addResponse(ChannelContext channelContext, HttpResponse response)
method domainListRemove (line 183) | void domainListRemove(List<HttpRequest> list)
method sequenceRemove (line 189) | void sequenceRemove(List<HttpRequest> list)
method search (line 194) | void search(SearchModel searchModel)
method currentView (line 199) | List<HttpRequest>? currentView()
method clean (line 204) | void clean()
method cleanupEarlyData (line 213) | void cleanupEarlyData(int retain)
method export (line 226) | Future<void> export(String fileName)
method repeatAllRequests (line 243) | void repeatAllRequests()
FILE: lib/ui/desktop/request/repeat.dart
class CustomRepeatDialog (line 28) | class CustomRepeatDialog extends StatefulWidget {
method createState (line 35) | State<StatefulWidget> createState()
class _CustomRepeatState (line 38) | class _CustomRepeatState extends State<CustomRepeatDialog> {
method initState (line 55) | void initState()
method dispose (line 72) | void dispose()
method _two (line 80) | String _two(int v)
method build (line 83) | Widget build(BuildContext context)
method submitTask (line 238) | void submitTask(int counter)
method _pickScheduleDateTime (line 259) | Future<void> _pickScheduleDateTime()
method field (line 312) | Widget field(String label, Widget child)
method textField (line 321) | Widget textField(TextEditingController? controller, {TextStyle? style})
FILE: lib/ui/desktop/request/report_servers.dart
function showReportServersDialog (line 14) | Future<void> showReportServersDialog(BuildContext context)
class ReportServersPage (line 31) | class ReportServersPage extends StatefulWidget {
method createState (line 35) | State<ReportServersPage> createState()
class _ReportServersPageState (line 38) | class _ReportServersPageState extends State<ReportServersPage> {
method _openGuide (line 44) | Future<void> _openGuide()
method initState (line 60) | void initState()
method _load (line 65) | Future<void> _load()
method focusedBorder (line 74) | InputBorder focusedBorder()
method _showServerDialog (line 79) | Future<ReportServer?> _showServerDialog({ReportServer? initial})
method dec (line 87) | InputDecoration dec({String? hint})
method labeled (line 96) | Widget labeled(String label, Widget field, {bool expanded = true})
method _addServerDialog (line 210) | Future<void> _addServerDialog()
method _editServerDialog (line 219) | Future<void> _editServerDialog(int index)
method _confirmDelete (line 229) | Future<void> _confirmDelete(int index)
method build (line 239) | Widget build(BuildContext context)
FILE: lib/ui/desktop/request/request.dart
class RequestWidget (line 55) | class RequestWidget extends StatefulWidget {
method createState (line 70) | State<RequestWidget> createState()
method setResponse (line 72) | void setResponse(HttpResponse response)
class _RequestWidgetState (line 79) | class _RequestWidgetState extends State<RequestWidget> {
method initState (line 92) | void initState()
method dispose (line 97) | void dispose()
method build (line 103) | Widget build(BuildContext context)
method color (line 145) | Color? color(String url)
method changeState (line 158) | void changeState()
method contextualMenu (line 162) | void contextualMenu()
method highlightMenu (line 282) | Menu highlightMenu()
method showCustomRepeat (line 348) | Future<void> showCustomRepeat(HttpRequest request)
method onRepeat (line 359) | void onRepeat(HttpRequest httpRequest)
method popupItem (line 366) | PopupMenuItem popupItem(String text, {VoidCallback? onTap})
method requestEdit (line 371) | Future<void> requestEdit()
method openDetailInNewWindow (line 390) | void openDetailInNewWindow()
method onClick (line 403) | void onClick()
FILE: lib/ui/desktop/request/request_editor.dart
type RequestEditorSource (line 39) | enum RequestEditorSource {
class RequestEditor (line 46) | class RequestEditor extends StatefulWidget {
method createState (line 65) | State<StatefulWidget> createState()
class RequestEditorState (line 70) | class RequestEditorState extends State<RequestEditor> {
method initState (line 86) | void initState()
method onKeyEvent (line 99) | bool onKeyEvent(KeyEvent event)
method dispose (line 128) | void dispose()
method build (line 145) | Widget build(BuildContext context)
method sendRequest (line 245) | Future<void> sendRequest()
method executeBreakpoint (line 273) | void executeBreakpoint()
method curlParse (line 301) | Future<void> curlParse()
type ParamCallback (line 344) | typedef ParamCallback = void Function(String param);
class UrlQueryNotifier (line 346) | class UrlQueryNotifier {
method urlListener (line 350) | ParamCallback urlListener(ParamCallback listener)
method paramListener (line 352) | ParamCallback paramListener(ParamCallback listener)
method onUrlChange (line 354) | void onUrlChange(String url)
method onParamChange (line 356) | void onParamChange(String param)
class _HttpWidget (line 359) | class _HttpWidget extends StatefulWidget {
method createState (line 368) | State<StatefulWidget> createState()
class _HttpState (line 373) | class _HttpState extends State<_HttpWidget> {
method getBody (line 382) | String? getBody()
method getHeaders (line 386) | HttpHeaders? getHeaders()
method initState (line 391) | void initState()
method change (line 406) | void change(HttpMessage? message)
method build (line 413) | Widget build(BuildContext context)
method _body (line 453) | Widget _body()
class _RequestLine (line 464) | class _RequestLine extends StatefulWidget {
method createState (line 471) | State<StatefulWidget> createState()
class _RequestLineState (line 476) | class _RequestLineState extends State<_RequestLine> {
method initState (line 481) | void initState()
method change (line 500) | void change(String? requestUrl, HttpMethod? requestMethod)
method urlNotifier (line 507) | void urlNotifier()
method onQueryChange (line 512) | void onQueryChange(String query)
method build (line 524) | Widget build(BuildContext context)
class KeyVal (line 547) | class KeyVal {
class KeyValWidget (line 558) | class KeyValWidget extends StatefulWidget {
method createState (line 567) | State<StatefulWidget> createState()
class KeyValState (line 570) | class KeyValState extends State<KeyValWidget> with AutomaticKeepAliveCli...
method initState (line 579) | void initState()
method onChange (line 603) | void onChange(String value)
method notifierChange (line 624) | void notifierChange()
method clear (line 633) | void clear()
method refreshParam (line 642) | void refreshParam(Map<String, List<String>>? headers)
method getParams (line 655) | Map<String, List<String>> getParams()
method build (line 669) | Widget build(BuildContext context)
method _buildRows (line 701) | List<Widget> _buildRows()
method _cell (line 725) | Widget _cell(KeyVal keyVal,
method _row (line 837) | Widget _row(KeyVal keyVal, Widget? op)
method _buildHighlightText (line 868) | Widget _buildHighlightText(String text, String query)
FILE: lib/ui/desktop/request/request_sequence.dart
class RequestSequence (line 32) | class RequestSequence extends StatefulWidget {
method createState (line 42) | State<StatefulWidget> createState()
class RequestSequenceState (line 47) | class RequestSequenceState extends State<RequestSequence> with Automatic...
method initState (line 63) | void initState()
method dispose (line 93) | void dispose()
method build (line 99) | Widget build(BuildContext context)
method appIcon (line 123) | Widget? appIcon(HttpRequest request)
method highlightHandler (line 142) | void highlightHandler()
method add (line 147) | void add(HttpRequest request)
method addResponse (line 163) | void addResponse(HttpResponse response)
method search (line 179) | void search(SearchModel searchModel)
method remove (line 189) | void remove(List<HttpRequest> list)
method clean (line 195) | void clean()
method sort (line 203) | void sort(bool desc)
FILE: lib/ui/desktop/request/search.dart
class Search (line 27) | class Search extends StatefulWidget {
method createState (line 33) | State<StatefulWidget> createState()
class SearchState (line 38) | class SearchState extends State<Search> {
method build (line 45) | Widget build(BuildContext context)
method searchDialog (line 98) | void searchDialog([TapDownDetails? details])
class ContentTypeSelect (line 133) | class ContentTypeSelect extends StatefulWidget {
method createState (line 139) | State<StatefulWidget> createState()
class ContentTypeState (line 144) | class ContentTypeState extends State<ContentTypeSelect> {
method initState (line 151) | void initState()
method build (line 156) | Widget build(BuildContext context)
method item (line 184) | PopupMenuItem<String> item(String value)
FILE: lib/ui/desktop/setting/about.dart
class DesktopAbout (line 7) | class DesktopAbout extends StatefulWidget {
method createState (line 11) | State<StatefulWidget> createState()
class _AppUpdateStateChecking (line 16) | class _AppUpdateStateChecking extends State<DesktopAbout> {
method build (line 22) | Widget build(BuildContext context)
method _safeLaunch (line 113) | Future<void> _safeLaunch(Uri uri)
method _showSponsorDialog (line 117) | void _showSponsorDialog()
FILE: lib/ui/desktop/setting/external_proxy.dart
class ExternalProxyDialog (line 27) | class ExternalProxyDialog extends StatefulWidget {
method createState (line 33) | State<StatefulWidget> createState()
class _ExternalProxyDialogState (line 38) | class _ExternalProxyDialogState extends State<ExternalProxyDialog> {
method initState (line 45) | void initState()
method build (line 54) | Widget build(BuildContext context)
FILE: lib/ui/desktop/setting/filter.dart
class FilterDialog (line 33) | class FilterDialog extends StatefulWidget {
method createState (line 39) | State<FilterDialog> createState()
class _FilterDialogState (line 42) | class _FilterDialogState extends State<FilterDialog> {
method dispose (line 48) | void dispose()
method build (line 54) | Widget build(BuildContext context)
class DomainFilter (line 95) | class DomainFilter extends StatefulWidget {
method createState (line 111) | State<StatefulWidget> createState()
class _DomainFilterState (line 116) | class _DomainFilterState extends State<DomainFilter> {
method dispose (line 122) | void dispose()
method build (line 130) | Widget build(BuildContext context)
method add (line 191) | void add()
class DomainAddDialog (line 205) | class DomainAddDialog extends StatelessWidget {
method build (line 212) | Widget build(BuildContext context)
class DomainList (line 254) | class DomainList extends StatefulWidget {
method createState (line 261) | State<StatefulWidget> createState()
class _DomainListState (line 264) | class _DomainListState extends State<DomainList> {
method build (line 279) | Widget build(BuildContext context)
method rows (line 320) | List<Widget> rows(List<RegExp> list)
method remove (line 394) | Future<void> remove(List<int> indexes)
FILE: lib/ui/desktop/setting/hosts.dart
class HostsDialog (line 33) | class HostsDialog extends StatefulWidget {
method createState (line 39) | State<HostsDialog> createState()
class _HostsDialogState (line 42) | class _HostsDialogState extends State<HostsDialog> {
method build (line 63) | Widget build(BuildContext context)
method row (line 160) | Widget row(HostsItem item, bool isEven, {EdgeInsetsGeometry? padding})
method removeHosts (line 330) | Future<void> removeHosts(Set<HostsItem> items)
class FolderDialog (line 402) | class FolderDialog extends StatelessWidget {
method build (line 409) | Widget build(BuildContext context)
class HostsEditDialog (line 452) | class HostsEditDialog extends StatefulWidget {
method createState (line 459) | State<HostsEditDialog> createState()
class _HostsEditDialogState (line 462) | class _HostsEditDialogState extends State<HostsEditDialog> {
method initState (line 472) | void initState()
method dispose (line 482) | void dispose()
method build (line 489) | Widget build(BuildContext context)
FILE: lib/ui/desktop/setting/request_block.dart
class RequestBlock (line 22) | class RequestBlock extends StatefulWidget {
method createState (line 28) | State<RequestBlock> createState()
class _RequestBlockState (line 31) | class _RequestBlockState extends State<RequestBlock> {
method initState (line 36) | void initState()
method dispose (line 41) | void dispose()
method build (line 49) | Widget build(BuildContext context)
method row (line 101) | Widget row(int index)
class RequestBlockAddDialog (line 180) | class RequestBlockAddDialog extends StatelessWidget {
method build (line 187) | Widget build(BuildContext context)
FILE: lib/ui/desktop/setting/request_breakpoint.dart
class RequestBreakpointPage (line 18) | class RequestBreakpointPage extends StatefulWidget {
method createState (line 25) | State<RequestBreakpointPage> createState()
class _RequestBreakpointPageState (line 28) | class _RequestBreakpointPageState extends State<RequestBreakpointPage> {
method _refreshConfig (line 39) | Future<void> _refreshConfig()
method _save (line 45) | Future<void> _save()
method _import (line 50) | Future<void> _import()
method _export (line 82) | Future<void> _export(List<RequestBreakpointRule> exportRules)
method initState (line 104) | void initState()
method dispose (line 112) | void dispose()
method onKeyEvent (line 117) | bool onKeyEvent(KeyEvent event)
method build (line 138) | Widget build(BuildContext context)
method _buildList (line 183) | Widget _buildList()
method _buildRow (line 239) | Widget _buildRow(int index)
method _showMenu (line 306) | void _showMenu(Offset position, {int? index})
method _editRule (line 361) | void _editRule({RequestBreakpointRule? rule})
class InterceptRuleDialog (line 378) | class InterceptRuleDialog extends StatefulWidget {
method createState (line 384) | State<InterceptRuleDialog> createState()
class _InterceptRuleDialogState (line 387) | class _InterceptRuleDialogState extends State<InterceptRuleDialog> {
method initState (line 402) | void initState()
method decoration (line 412) | InputDecoration decoration(String label, {String? hintText})
method build (line 422) | Widget build(BuildContext context)
method textField (line 551) | Widget textField(String label, TextEditingController controller, Strin...
method focusedBorder (line 573) | InputBorder focusedBorder()
FILE: lib/ui/desktop/setting/request_crypto.dart
function _refreshConfig (line 20) | Future<void> _refreshConfig({bool force = false})
class RequestCryptoPage (line 39) | class RequestCryptoPage extends StatefulWidget {
method createState (line 46) | State<RequestCryptoPage> createState()
class _RequestCryptoPageState (line 49) | class _RequestCryptoPageState extends State<RequestCryptoPage> {
method initState (line 55) | void initState()
method dispose (line 61) | void dispose()
method _onKeyEvent (line 66) | bool _onKeyEvent(KeyEvent event)
method build (line 85) | Widget build(BuildContext context)
method _addRule (line 127) | Future<void> _addRule()
method _import (line 136) | Future<void> _import()
class CryptoRuleList (line 165) | class CryptoRuleList extends StatefulWidget {
method createState (line 176) | State<CryptoRuleList> createState()
class _CryptoRuleListState (line 179) | class _CryptoRuleListState extends State<CryptoRuleList> {
method build (line 188) | Widget build(BuildContext context)
method rows (line 241) | List<Widget> rows(List<CryptoRule> rules)
method showEdit (line 312) | Future<void> showEdit([int? index])
method removeRules (line 329) | Future<void> removeRules(List<int> indexes)
method showMenus (line 341) | void showMenus(TapDownDetails details, int index)
method showGlobalMenu (line 356) | void showGlobalMenu(Offset offset)
method enableStatus (line 368) | Future<void> enableStatus(bool enable)
method export (line 377) | Future<void> export(List<int> indexes)
method _formatKey (line 394) | String _formatKey(String? raw)
class CryptoRuleDialog (line 405) | class CryptoRuleDialog extends StatefulWidget {
method createState (line 411) | State<CryptoRuleDialog> createState()
class _CryptoRuleDialogState (line 414) | class _CryptoRuleDialogState extends State<CryptoRuleDialog> {
method initState (line 433) | void initState()
method dispose (line 470) | void dispose()
method decorate (line 479) | InputDecoration decorate(BuildContext context, String? label, {String?...
method build (line 490) | Widget build(BuildContext context)
FILE: lib/ui/desktop/setting/request_map.dart
function _refreshConfig (line 24) | Future<void> _refreshConfig({bool force = false})
class RequestMapPage (line 43) | class RequestMapPage extends StatefulWidget {
method createState (line 49) | State<StatefulWidget> createState()
class _RequestMapPageState (line 52) | class _RequestMapPageState extends State<RequestMapPage> {
method initState (line 56) | void initState()
method dispose (line 62) | void dispose()
method onKeyEvent (line 67) | bool onKeyEvent(KeyEvent event)
method build (line 87) | Widget build(BuildContext context)
method import (line 142) | Future<void> import()
method showEdit (line 182) | Future<void> showEdit()
class RequestMapList (line 193) | class RequestMapList extends StatefulWidget {
method createState (line 200) | State<RequestMapList> createState()
class _RequestMapListState (line 203) | class _RequestMapListState extends State<RequestMapList> {
method build (line 211) | Widget build(BuildContext context)
method rows (line 259) | List<Widget> rows(List<RequestMapRule> list)
method showGlobalMenu (line 325) | void showGlobalMenu(Offset offset)
method showMenus (line 338) | void showMenus(TapDownDetails details, int index)
method showEdit (line 375) | Future<void> showEdit([int? index])
method export (line 394) | Future<void> export(List<int> indexes)
method enableStatus (line 425) | void enableStatus(bool enable)
method remove (line 433) | Future<void> remove(List<int> indexes)
class RequestMapEdit (line 452) | class RequestMapEdit extends StatefulWidget {
method createState (line 462) | State<StatefulWidget> createState()
class _RequestMapEditState (line 467) | class _RequestMapEditState extends State<RequestMapEdit> {
method initState (line 480) | void initState()
method dispose (line 489) | void dispose()
method build (line 496) | Widget build(BuildContext context)
method onChangeType (line 591) | void onChangeType(RequestMapType? val)
method mapRule (line 597) | Widget mapRule()
method textField (line 605) | Widget textField(String label, TextEditingController controller, Strin...
method focusedBorder (line 628) | InputBorder focusedBorder()
FILE: lib/ui/desktop/setting/request_map/map_local.dart
class DesktopMapLocal (line 32) | class DesktopMapLocal extends StatefulWidget {
method createState (line 39) | State<DesktopMapLocal> createState()
class MapLocaleState (line 42) | class MapLocaleState extends State<DesktopMapLocal> {
method initItem (line 66) | void initItem(RequestMapItem? item)
method getRequestMapItem (line 78) | RequestMapItem getRequestMapItem()
method build (line 94) | Widget build(BuildContext context)
method tabBar (line 114) | TabBar tabBar(List<String> tabs)
method body (line 125) | Widget body()
method fileBodyEdit (line 161) | Widget fileBodyEdit()
method headers (line 202) | Widget headers()
method textField (line 206) | Widget textField(String label, dynamic value, String hint, {ValueChang...
method statusCodeEdit (line 225) | Widget statusCodeEdit()
method decoration (line 249) | InputDecoration decoration(String label, {String? hintText})
method focusedBorder (line 263) | InputBorder focusedBorder()
class Headers (line 269) | class Headers extends StatefulWidget {
method createState (line 275) | State<StatefulWidget> createState()
class HeadersState (line 280) | class HeadersState extends State<Headers> with AutomaticKeepAliveClientM...
method initState (line 289) | void initState()
method setHeaders (line 299) | void setHeaders(Map<String, String>? headers)
method getHeaders (line 308) | Map<String, String> getHeaders()
method _clear (line 325) | void _clear()
method build (line 334) | Widget build(BuildContext context)
method _buildRows (line 360) | List<Widget> _buildRows()
method _cell (line 381) | Widget _cell(TextEditingController val, {bool isKey = false})
method _row (line 397) | Widget _row(Widget key, Widget val, Widget? op)
FILE: lib/ui/desktop/setting/request_map/map_scipt.dart
class DesktopMapScript (line 7) | class DesktopMapScript extends StatefulWidget {
method createState (line 13) | State<StatefulWidget> createState()
class MapScriptState (line 16) | class MapScriptState extends State<DesktopMapScript> {
method getScriptCode (line 37) | String getScriptCode()
method initState (line 42) | void initState()
method dispose (line 48) | void dispose()
method build (line 54) | Widget build(BuildContext context)
FILE: lib/ui/desktop/setting/request_rewrite.dart
class RequestRewriteWidget (line 41) | class RequestRewriteWidget extends StatefulWidget {
method createState (line 48) | State<StatefulWidget> createState()
class RequestRewriteState (line 53) | class RequestRewriteState extends State<RequestRewriteWidget> {
method initState (line 59) | void initState()
method dispose (line 66) | void dispose()
method onKeyEvent (line 71) | bool onKeyEvent(KeyEvent event)
method build (line 92) | Widget build(BuildContext context)
method refresh (line 151) | void refresh()
method import (line 157) | Future<void> import()
method add (line 196) | void add()
class RequestRuleList (line 207) | class RequestRuleList extends StatefulWidget {
method createState (line 214) | State<RequestRuleList> createState()
class _RequestRuleListState (line 217) | class _RequestRuleListState extends State<RequestRuleList> {
method build (line 232) | Widget build(BuildContext context)
method enableStatus (line 280) | void enableStatus(bool enable)
method showGlobalMenu (line 292) | void showGlobalMenu(Offset offset)
method rows (line 305) | List<Widget> rows(List<RequestRewriteRule> list)
method export (line 371) | Future<void> export(List<int> indexes)
method removeRewrite (line 402) | Future<void> removeRewrite(List<int> indexes)
method showEdit (line 420) | Future<void> showEdit([int? index])
method showMenus (line 442) | void showMenus(TapDownDetails details, int index)
class RewriteRuleEdit (line 478) | class RewriteRuleEdit extends StatefulWidget {
method createState (line 487) | State<StatefulWidget> createState()
class _RewriteRuleEditState (line 492) | class _RewriteRuleEditState extends State<RewriteRuleEdit> {
method initState (line 506) | void initState()
method dispose (line 520) | void dispose()
method build (line 527) | Widget build(BuildContext context)
method onChangeType (line 663) | void onChangeType(RuleType? val)
method fromRequestItems (line 681) | List<RewriteItem> fromRequestItems(HttpRequest request, RuleType ruleT...
method rewriteRule (line 692) | Widget rewriteRule()
method textField (line 700) | Widget textField(String label, TextEditingController controller, Strin...
method focusedBorder (line 722) | InputBorder focusedBorder()
FILE: lib/ui/desktop/setting/rewrite/rewrite_replace.dart
class DesktopRewriteReplace (line 32) | class DesktopRewriteReplace extends StatefulWidget {
method createState (line 40) | State<DesktopRewriteReplace> createState()
class RewriteReplaceState (line 43) | class RewriteReplaceState extends State<DesktopRewriteReplace> {
method _initRewriteItem (line 88) | RewriteItem _initRewriteItem(List<RewriteItem>? items, RewriteType typ...
method getItems (line 105) | List<RewriteItem> getItems()
method build (line 117) | Widget build(BuildContext context)
method tabBar (line 149) | TabBar tabBar(List<String> tabs)
method body (line 165) | Widget body()
method fileBodyEdit (line 231) | Widget fileBodyEdit(RewriteItem item)
method headers (line 273) | Widget headers()
method requestLine (line 298) | Widget requestLine()
method redirectEdit (line 347) | Widget redirectEdit(RewriteItem rewriteItem)
method textField (line 362) | Widget textField(String label, dynamic value, String hint, {ValueChang...
method statusCodeEdit (line 381) | Widget statusCodeEdit()
method decoration (line 419) | InputDecoration decoration(String label, {String? hintText})
method focusedBorder (line 432) | InputBorder focusedBorder()
class Headers (line 438) | class Headers extends StatefulWidget {
method createState (line 444) | State<StatefulWidget> createState()
class HeadersState (line 449) | class HeadersState extends State<Headers> with AutomaticKeepAliveClientM...
method initState (line 458) | void initState()
method getHeaders (line 475) | Map<String, String> getHeaders()
method build (line 501) | Widget build(BuildContext context)
method _buildRows (line 527) | List<Widget> _buildRows()
method _cell (line 548) | Widget _cell(TextEditingController val, {bool isKey = false})
method _row (line 563) | Widget _row(Widget key, Widget val, Widget? op)
FILE: lib/ui/desktop/setting/rewrite/rewrite_update.dart
class DesktopRewriteUpdate (line 30) | class DesktopRewriteUpdate extends StatefulWidget {
method createState (line 38) | State<DesktopRewriteUpdate> createState()
class RewriteUpdateState (line 41) | class RewriteUpdateState extends State<DesktopRewriteUpdate> {
method initState (line 48) | void initState()
method getItems (line 67) | List<RewriteItem> getItems()
method build (line 72) | Widget build(BuildContext context)
class RewriteUpdateAddDialog (line 103) | class RewriteUpdateAddDialog extends StatefulWidget {
method createState (line 111) | State<RewriteUpdateAddDialog> createState()
class _RewriteUpdateAddState (line 114) | class _RewriteUpdateAddState extends State<RewriteUpdateAddDialog> {
method initState (line 127) | void initState()
method dispose (line 140) | void dispose()
method build (line 148) | Widget build(BuildContext context)
method textField (line 329) | Widget textField(String label, String hint, {bool required = false, in...
method formField (line 336) | Widget formField(String hint, {bool required = false, int? lines, Text...
method focusedBorder (line 354) | InputBorder focusedBorder()
class UpdateList (line 359) | class UpdateList extends StatefulWidget {
method createState (line 367) | State<UpdateList> createState()
class _UpdateListState (line 370) | class _UpdateListState extends State<UpdateList> {
method initState (line 374) | void initState()
method build (line 379) | Widget build(BuildContext context)
method rows (line 402) | List<Widget> rows(List<RewriteItem> list)
method getText (line 447) | String getText(RewriteItem item)
FILE: lib/ui/desktop/setting/script.dart
function _refreshScript (line 42) | Future<void> _refreshScript({bool force = false})
class ScriptWidget (line 61) | class ScriptWidget extends StatefulWidget {
method createState (line 67) | State<ScriptWidget> createState()
class _ScriptWidgetState (line 70) | class _ScriptWidgetState extends State<ScriptWidget> {
method initState (line 74) | void initState()
method dispose (line 80) | void dispose()
method onKeyEvent (line 85) | bool onKeyEvent(KeyEvent event)
method build (line 105) | Widget build(BuildContext context)
method consoleLog (line 164) | void consoleLog()
method import (line 169) | Future<void> import()
method scriptAdd (line 212) | Future<void> scriptAdd()
class ScriptConsoleWidget (line 221) | class ScriptConsoleWidget extends StatefulWidget {
method createState (line 227) | State<ScriptConsoleWidget> createState()
class _ScriptConsoleState (line 230) | class _ScriptConsoleState extends State<ScriptConsoleWidget> {
method initState (line 238) | void initState()
method build (line 262) | Widget build(BuildContext context)
class ScriptEdit (line 325) | class ScriptEdit extends StatefulWidget {
method createState (line 348) | State<StatefulWidget> createState()
class _ScriptEditState (line 351) | class _ScriptEditState extends State<ScriptEdit> {
method _fetchRemoteScript (line 361) | Future<void> _fetchRemoteScript()
method _resetScript (line 395) | void _resetScript()
method initState (line 401) | void initState()
method dispose (line 416) | void dispose()
method build (line 429) | Widget build(BuildContext context)
method textField (line 684) | Widget textField(String label, TextEditingController controller, Strin...
method focusedBorder (line 704) | InputBorder focusedBorder()
class ScriptList (line 710) | class ScriptList extends StatefulWidget {
method createState (line 717) | State<ScriptList> createState()
class _ScriptListState (line 720) | class _ScriptListState extends State<ScriptList> {
method build (line 728) | Widget build(BuildContext context)
method rows (line 772) | List<Widget> rows(List<ScriptItem> list)
method showGlobalMenu (line 845) | void showGlobalMenu(Offset offset)
method showMenus (line 858) | void showMenus(TapDownDetails details, int index)
method showEdit (line 895) | Future<void> showEdit([int? index])
method export (line 920) | Future<void> export(List<int> indexes)
method enableStatus (line 952) | void enableStatus(bool enable)
method removeScripts (line 960) | Future<void> removeScripts(List<int> indexes)
FILE: lib/ui/desktop/setting/setting.dart
class Setting (line 36) | class Setting extends StatefulWidget {
method createState (line 42) | State<Setting> createState()
class _SettingState (line 45) | class _SettingState extends State<Setting> {
method initState (line 51) | void initState()
method build (line 57) | Widget build(BuildContext context)
method item (line 88) | Widget item(String text, {VoidCallback? onPressed})
method showAbout (line 97) | void showAbout()
method setExternalProxy (line 102) | void setExternalProxy()
method requestRewrite (line 112) | void requestRewrite()
method requestBreakpoint (line 116) | void requestBreakpoint()
method requestMap (line 121) | void requestMap()
method hostFilter (line 127) | void hostFilter()
method hosts (line 133) | void hosts()
method showRequestBlock (line 140) | void showRequestBlock()
method showRequestCrypto (line 149) | void showRequestCrypto()
class _ProxyMenu (line 155) | class _ProxyMenu extends StatefulWidget {
method createState (line 161) | State<StatefulWidget> createState()
class _ProxyMenuState (line 164) | class _ProxyMenuState extends State<_ProxyMenu> {
method initState (line 173) | void initState()
method dispose (line 180) | void dispose()
method build (line 195) | Widget build(BuildContext context)
method setSystemProxy (line 276) | Widget setSystemProxy()
FILE: lib/ui/desktop/ssl/cert_installer.dart
class CertInstaller (line 5) | class CertInstaller {
method installCertificate (line 6) | Future<bool> installCertificate(File certFile)
method isCertInstalled (line 55) | Future<bool> isCertInstalled(File filePath, X509CertificateData caCert)
FILE: lib/ui/desktop/ssl/pc_cert.dart
class PCCertChecker (line 17) | class PCCertChecker {
method check (line 20) | void check(BuildContext context)
class PCCert (line 68) | class PCCert extends StatefulWidget {
method createState (line 72) | State<PCCert> createState()
class _PCCertState (line 75) | class _PCCertState extends State<PCCert> with TickerProviderStateMixin {
method initState (line 79) | void initState()
method build (line 85) | Widget build(BuildContext context)
method _buildManualTab (line 121) | Widget _buildManualTab(BuildContext context)
method _buildChildren (line 133) | List<Widget> _buildChildren(BuildContext context)
method _buildWindowsAndMacContent (line 140) | List<Widget> _buildWindowsAndMacContent(BuildContext context)
method _buildLinuxContent (line 170) | List<Widget> _buildLinuxContent(BuildContext context)
method _manualInstallCert (line 198) | void _manualInstallCert()
class _AutomaticInstall (line 206) | class _AutomaticInstall extends StatefulWidget {
method createState (line 208) | State<StatefulWidget> createState()
class _AutomaticInstallState (line 211) | class _AutomaticInstallState extends State<_AutomaticInstall> {
method initState (line 216) | void initState()
method _checkCertStatus (line 228) | void _checkCertStatus()
method build (line 235) | Widget build(BuildContext context)
method buildAutomaticChildren (line 242) | List<Widget> buildAutomaticChildren()
method _installCert (line 324) | void _installCert(BuildContext context)
FILE: lib/ui/desktop/ssl/ssl.dart
class SslWidget (line 15) | class SslWidget extends StatefulWidget {
method createState (line 21) | State<SslWidget> createState()
class _SslState (line 24) | class _SslState extends State<SslWidget> {
method build (line 28) | Widget build(BuildContext context)
method importMenu (line 75) | Widget importMenu()
method exportMenu (line 125) | Widget exportMenu()
method item (line 199) | Widget item(String text, {VoidCallback? onPressed})
method iosCer (line 207) | void iosCer(String host)
method androidCer (line 256) | void androidCer(String host)
class _Switch (line 351) | class _Switch extends StatefulWidget {
method createState (line 358) | State<_Switch> createState()
class _SwitchState (line 361) | class _SwitchState extends State<_Switch> {
method build (line 367) | Widget build(BuildContext context)
method dispose (line 390) | void dispose()
FILE: lib/ui/desktop/toolbar/phone_connect.dart
class PhoneConnect (line 23) | class PhoneConnect extends StatefulWidget {
method createState (line 30) | State<StatefulWidget> createState()
class _PhoneConnectState (line 35) | class _PhoneConnectState extends State<PhoneConnect> {
method initState (line 42) | void initState()
method build (line 49) | Widget build(BuildContext context)
FILE: lib/ui/desktop/toolbar/toolbar.dart
class Toolbar (line 33) | class Toolbar extends StatefulWidget {
method createState (line 40) | State<StatefulWidget> createState()
class _ToolbarState (line 45) | class _ToolbarState extends State<Toolbar> {
method initState (line 49) | void initState()
method onKeyEvent (line 54) | bool onKeyEvent(KeyEvent event)
method dispose (line 76) | void dispose()
method build (line 82) | Widget build(BuildContext context)
method phoneConnect (line 109) | void phoneConnect(List<String> hosts, int port)
FILE: lib/ui/desktop/widgets/highlight.dart
class DesktopKeywordHighlight (line 8) | class DesktopKeywordHighlight extends StatefulWidget {
method createState (line 12) | State<DesktopKeywordHighlight> createState()
class _KeywordHighlightState (line 15) | class _KeywordHighlightState extends State<DesktopKeywordHighlight> {
method build (line 17) | Widget build(BuildContext context)
method decoration (line 81) | InputDecoration decoration(String label, {String? hintText})
FILE: lib/ui/desktop/widgets/windows_toolbar.dart
class WindowsToolbar (line 4) | class WindowsToolbar extends StatefulWidget {
method createState (line 13) | State<WindowsToolbar> createState()
class _WindowsToolbarState (line 16) | class _WindowsToolbarState extends State<WindowsToolbar> with WindowList...
method initState (line 18) | void initState()
method dispose (line 24) | void dispose()
method build (line 30) | Widget build(BuildContext context)
method onWindowMaximize (line 81) | void onWindowMaximize()
method onWindowUnmaximize (line 86) | void onWindowUnmaximize()
FILE: lib/ui/desktop/window_listener.dart
class WindowChangeListener (line 22) | class WindowChangeListener extends WindowListener {
method onWindowResized (line 28) | void onWindowResized()
method onWindowMoved (line 36) | void onWindowMoved()
FILE: lib/ui/launch/launch.dart
class SocketLaunch (line 36) | class SocketLaunch extends StatefulWidget {
method createState (line 57) | State<StatefulWidget> createState()
class _SocketLaunchState (line 60) | class _SocketLaunchState extends State<SocketLaunch> with WindowListener...
method initState (line 65) | void initState()
method dispose (line 89) | void dispose()
method onWindowClose (line 96) | void onWindowClose()
method appExit (line 101) | Future<void> appExit()
method didRequestAppExit (line 122) | Future<AppExitResponse> didRequestAppExit()
method didChangeAppLifecycleState (line 128) | void didChangeAppLifecycleState(AppLifecycleState state)
method build (line 151) | Widget build(BuildContext context)
method start (line 180) | Future<void> start()
FILE: lib/ui/mobile/debug/breakpoint_executor.dart
class BreakpointExecutor (line 8) | class BreakpointExecutor extends StatefulWidget {
method createState (line 25) | State<BreakpointExecutor> createState()
class _BreakpointExecutorState (line 28) | class _BreakpointExecutorState extends State<BreakpointExecutor> {
method initState (line 33) | void initState()
method build (line 40) | Widget build(BuildContext context)
method _buildResponseBody (line 58) | Widget _buildResponseBody()
FILE: lib/ui/mobile/menu/bottom_navigation.dart
class ConfigPage (line 50) | class ConfigPage extends StatefulWidget {
method createState (line 56) | State<StatefulWidget> createState()
class _ConfigPageState (line 59) | class _ConfigPageState extends State<ConfigPage> {
method initState (line 64) | void initState()
method build (line 70) | Widget build(BuildContext context)
method section (line 75) | Widget section(List<Widget> tiles)
function navigator (line 181) | void navigator(BuildContext context, Widget widget)
class SettingPage (line 189) | class SettingPage extends StatelessWidget {
method build (line 196) | Widget build(BuildContext context)
method section (line 204) | Widget section(List<Widget> tiles)
FILE: lib/ui/mobile/menu/drawer.dart
class DrawerWidget (line 53) | class DrawerWidget extends StatelessWidget {
method build (line 62) | Widget build(BuildContext context)
function navigator (line 196) | void navigator(BuildContext context, Widget widget)
class _SettingPage (line 204) | class _SettingPage extends StatelessWidget {
method build (line 211) | Widget build(BuildContext context)
method section (line 218) | Widget section(List<Widget> tiles)
class FilterMenu (line 347) | class FilterMenu extends StatelessWidget {
method build (line 353) | Widget build(BuildContext context)
FILE: lib/ui/mobile/menu/menu.dart
class MoreMenu (line 30) | class MoreMenu extends StatelessWidget {
method build (line 39) | Widget build(BuildContext context)
method navigator (line 145) | void navigator(BuildContext context, Widget widget)
FILE: lib/ui/mobile/mobile.dart
class MobileHomePage (line 59) | class MobileHomePage extends StatefulWidget {
method createState (line 66) | State<StatefulWidget> createState()
class MobileApp (line 71) | class MobileApp {
class MobileHomeState (line 82) | class MobileHomeState extends State<MobileHomePage> implements EventList...
method onRequest (line 91) | void onRequest(Channel channel, HttpRequest request)
method onResponse (line 102) | void onResponse(ChannelContext channelContext, HttpResponse response)
method onMessage (line 107) | void onMessage(Channel channel, HttpMessage message, WebSocketFrame fr...
method initState (line 115) | void initState()
method dispose (line 152) | void dispose()
method build (line 165) | Widget build(BuildContext context)
method onUserLeaveHint (line 260) | void onUserLeaveHint()
method enterPictureInPicture (line 264) | Future<bool> enterPictureInPicture()
method showUpgradeNotice (line 307) | void showUpgradeNotice()
method showAlertDialog (line 332) | void showAlertDialog(String title, String content, Function onClose)
class RequestPage (line 353) | class RequestPage extends StatefulWidget {
method createState (line 360) | State<RequestPage> createState()
class RequestPageState (line 363) | class RequestPageState extends State<RequestPage> {
method initState (line 372) | void initState()
method dispose (line 388) | void dispose()
method build (line 394) | Widget build(BuildContext context)
method _launchActionButton (line 417) | Widget _launchActionButton()
method remoteConnect (line 448) | Widget remoteConnect(RemoteModel value)
method checkConnectTask (line 466) | Future<void> checkConnectTask(BuildContext context)
class _MobileAppBar (line 504) | class _MobileAppBar extends StatelessWidget implements PreferredSizeWidg...
method build (line 515) | Widget build(BuildContext context)
FILE: lib/ui/mobile/request/domians.dart
class DomainList (line 36) | class DomainList extends StatefulWidget {
method createState (line 44) | State<StatefulWidget> createState()
class DomainListState (line 49) | class DomainListState extends State<DomainList> with AutomaticKeepAliveC...
method search (line 146) | void search(String? text)
method filter (line 173) | bool filter(HostAndPort hostAndPort)
method dispose (line 196) | void dispose()
method build (line 202) | Widget build(BuildContext context)
method title (line 216) | Widget title(int index)
method repeatDomainRequests (line 333) | void repeatDomainRequests(HostAndPort hostAndPort)
FILE: lib/ui/mobile/request/favorite.dart
class MobileFavorites (line 48) | class MobileFavorites extends StatefulWidget {
method createState (line 54) | State<StatefulWidget> createState()
class _FavoritesState (line 59) | class _FavoritesState extends State<MobileFavorites> {
method _exportJson (line 62) | Future<void> _exportJson()
method _materializePickedFile (line 71) | Future<String?> _materializePickedFile(PlatformFile file)
method build (line 80) | Widget build(BuildContext context)
class _FavoriteItem (line 147) | class _FavoriteItem extends StatefulWidget {
method createState (line 156) | State<_FavoriteItem> createState()
class _FavoriteItemState (line 159) | class _FavoriteItemState extends State<_FavoriteItem> {
method initState (line 166) | void initState()
method build (line 172) | Widget build(BuildContext context)
method menu (line 232) | void menu(details)
method showCustomRepeat (line 373) | void showCustomRepeat(HttpRequest request)
method onRepeat (line 380) | void onRepeat(HttpRequest request)
method rename (line 391) | void rename(Favorite item)
method onClick (line 420) | void onClick()
method itemButton (line 430) | Widget itemButton(
method menuItem (line 440) | Widget menuItem({required Widget left, required Widget right})
FILE: lib/ui/mobile/request/history.dart
class MobileHistory (line 44) | class MobileHistory extends StatefulWidget {
method createState (line 52) | State<StatefulWidget> createState()
function _repeatAllRequests (line 58) | void _repeatAllRequests(Iterable<HttpRequest> requests, ProxyServer prox...
class _MobileHistoryState (line 77) | class _MobileHistoryState extends State<MobileHistory> {
method initState (line 84) | void initState()
method build (line 92) | Widget build(BuildContext context)
method buildSaveSession (line 137) | Widget buildSaveSession(HistoryStorage storage)
method buildItem (line 182) | Widget buildItem(HistoryStorage storage, int index, HistoryItem item)
class HistoryRecord (line 309) | class HistoryRecord extends StatefulWidget {
method createState (line 316) | State<StatefulWidget> createState()
class _HistoryRecordState (line 321) | class _HistoryRecordState extends State<HistoryRecord> {
method dispose (line 332) | void dispose()
method build (line 338) | Widget build(BuildContext context)
FILE: lib/ui/mobile/request/list.dart
class RequestListWidget (line 36) | class RequestListWidget extends StatefulWidget {
method createState (line 43) | State<StatefulWidget> createState()
class RequestListState (line 48) | class RequestListState extends State<RequestListWidget> {
method initState (line 58) | void initState()
method build (line 66) | Widget build(BuildContext context)
method currentView (line 125) | Iterable<HttpRequest>? currentView()
class DoubleClickHandle (line 177) | class DoubleClickHandle {
method call (line 183) | void call()
FILE: lib/ui/mobile/request/repeat.dart
class MobileCustomRepeat (line 28) | class MobileCustomRepeat extends StatefulWidget {
method createState (line 35) | State<StatefulWidget> createState()
class _CustomRepeatState (line 38) | class _CustomRepeatState extends State<MobileCustomRepeat> {
method initState (line 53) | void initState()
method dispose (line 70) | void dispose()
method build (line 78) | Widget build(BuildContext context)
method _two (line 184) | String _two(int v)
method submitTask (line 187) | void submitTask(int counter)
method intervalWidget (line 209) | Widget intervalWidget()
method _pickScheduleDateTime (line 260) | Future<void> _pickScheduleDateTime()
method field (line 315) | Widget field(String label, Widget child)
method textField (line 324) | FormField textField(TextEditingController? controller, {TextStyle? sty...
FILE: lib/ui/mobile/request/request.dart
class RequestRow (line 47) | class RequestRow extends StatefulWidget {
method createState (line 63) | State<StatefulWidget> createState()
class RequestRowState (line 68) | class RequestRowState extends State<RequestRow> {
method change (line 79) | void change(HttpResponse response)
method initState (line 86) | void initState()
method dispose (line 93) | void dispose()
method color (line 98) | Color? color(String url)
method getContext (line 111) | BuildContext getContext()
method build (line 116) | Widget build(BuildContext context)
method appIcon (line 167) | Widget? appIcon()
method menu (line 193) | void menu(details)
method showCustomRepeat (line 356) | Future<void> showCustomRepeat(HttpRequest request)
method onRepeat (line 365) | void onRepeat(HttpRequest request)
method itemButton (line 375) | Widget itemButton(
method menuItem (line 385) | Widget menuItem({required Widget left, required Widget right})
FILE: lib/ui/mobile/request/request_editor.dart
class MobileRequestEditor (line 38) | class MobileRequestEditor extends StatefulWidget {
method createState (line 57) | State<StatefulWidget> createState()
class RequestEditorState (line 62) | class RequestEditorState extends State<MobileRequestEditor> with SingleT...
method dispose (line 85) | void dispose()
method initState (line 103) | void initState()
method curlParse (line 117) | Future<void> curlParse()
method build (line 158) | Widget build(BuildContext context)
method executeBreakpoint (line 267) | void executeBreakpoint()
type ParamCallback (line 295) | typedef ParamCallback = void Function(String param);
class UrlQueryNotifier (line 297) | class UrlQueryNotifier {
method urlListener (line 301) | ParamCallback urlListener(ParamCallback listener)
method paramListener (line 303) | ParamCallback paramListener(ParamCallback listener)
method onUrlChange (line 305) | void onUrlChange(String url)
method onParamChange (line 307) | void onParamChange(String param)
class _HttpWidget (line 310) | class _HttpWidget extends StatefulWidget {
method createState (line 319) | State<StatefulWidget> createState()
class _HttpState (line 324) | class _HttpState extends State<_HttpWidget> with AutomaticKeepAliveClien...
method getBody (line 335) | String? getBody()
method initState (line 340) | void initState()
method change (line 351) | void change(HttpMessage? message)
method getHeaders (line 358) | HttpHeaders? getHeaders()
method build (line 363) | Widget build(BuildContext context)
method _body (line 395) | Widget _body()
class _RequestLine (line 409) | class _RequestLine extends StatefulWidget {
method createState (line 416) | State<StatefulWidget> createState()
class _RequestLineState (line 421) | class _RequestLineState extends State<_RequestLine> {
method initState (line 426) | void initState()
method change (line 444) | void change(String? requestUrl, HttpMethod? requestMethod)
method urlNotifier (line 451) | void urlNotifier()
method onQueryChange (line 456) | void onQueryChange(String query)
method build (line 468) | Widget build(BuildContext context)
class KeyVal (line 496) | class KeyVal {
class KeyValWidget (line 505) | class KeyValWidget extends StatefulWidget {
method createState (line 523) | State<StatefulWidget> createState()
class KeyValState (line 530) | class KeyValState extends State<KeyValWidget> {
method initState (line 536) | void initState()
method onChange (line 549) | void onChange(String value)
method notifierChange (line 570) | void notifierChange()
method getParams (line 580) | Map<String, List<String>> getParams()
method refreshParam (line 594) | void refreshParam(Map<String, List<String>>? headers)
method build (line 606) | Widget build(BuildContext context)
method _buildRows (line 630) | List<Widget> _buildRows()
method hideKeyword (line 648) | void hideKeyword(BuildContext context)
method modifyParam (line 656) | void modifyParam(KeyVal keyVal)
method row (line 846) | Widget row(KeyVal keyVal)
method _buildHighlightText (line 867) | Widget _buildHighlightText(String text, String query)
FILE: lib/ui/mobile/request/request_editor_source.dart
type RequestEditorSource (line 1) | enum RequestEditorSource {
FILE: lib/ui/mobile/request/request_sequence.dart
class RequestSequence (line 14) | class RequestSequence extends StatefulWidget {
method createState (line 30) | State<StatefulWidget> createState()
class RequestSequenceState (line 35) | class RequestSequenceState extends State<RequestSequence> with Automatic...
method search (line 121) | void search(SearchModel searchModel)
method currentView (line 131) | Iterable<HttpRequest> currentView()
method build (line 151) | Widget build(BuildContext context)
FILE: lib/ui/mobile/request/search.dart
class MobileSearch (line 21) | class MobileSearch extends StatefulWidget {
method createState (line 28) | State<StatefulWidget> createState()
class MobileSearchState (line 33) | class MobileSearchState extends State<MobileSearch> {
method initState (line 40) | void initState()
method build (line 57) | Widget build(BuildContext context)
method showSearch (line 87) | void showSearch()
FILE: lib/ui/mobile/setting/app_filter.dart
class AppWhitelist (line 30) | class AppWhitelist extends StatefulWidget {
method createState (line 36) | State<AppWhitelist> createState()
class _AppWhitelistState (line 39) | class _AppWhitelistState extends State<AppWhitelist> {
method initState (line 47) | void initState()
method dispose (line 53) | void dispose()
method build (line 64) | Widget build(BuildContext context)
class AppBlacklist (line 178) | class AppBlacklist extends StatefulWidget {
method createState (line 184) | State<AppBlacklist> createState()
class _AppBlacklistState (line 187) | class _AppBlacklistState extends State<AppBlacklist> {
method initState (line 195) | void initState()
method dispose (line 201) | void dispose()
method build (line 212) | Widget build(BuildContext context)
class InstalledAppsWidget (line 309) | class InstalledAppsWidget extends StatefulWidget {
method createState (line 318) | State<InstalledAppsWidget> createState()
class _InstalledAppsWidgetState (line 321) | class _InstalledAppsWidgetState extends State<InstalledAppsWidget> {
method initState (line 330) | void initState()
method dispose (line 340) | void dispose()
method refreshApps (line 348) | void refreshApps()
method build (line 358) | Widget build(BuildContext context)
method buildAppListView (line 399) | ListView buildAppListView()
FILE: lib/ui/mobile/setting/filter.dart
class MobileFilterWidget (line 34) | class MobileFilterWidget extends StatefulWidget {
method createState (line 41) | State<MobileFilterWidget> createState()
class _MobileFilterState (line 44) | class _MobileFilterState extends State<MobileFilterWidget> {
method dispose (line 50) | void dispose()
method build (line 56) | Widget build(BuildContext context)
class DomainFilter (line 75) | class DomainFilter extends StatefulWidget {
method createState (line 91) | State<StatefulWidget> createState()
class _DomainFilterState (line 96) | class _DomainFilterState extends State<DomainFilter> {
method dispose (line 102) | void dispose()
method build (line 110) | Widget build(BuildContext context)
method add (line 164) | void add()
class DomainAddDialog (line 176) | class DomainAddDialog extends StatelessWidget {
method build (line 183) | Widget build(BuildContext context)
class DomainList (line 225) | class DomainList extends StatefulWidget {
method createState (line 232) | State<StatefulWidget> createState()
class _DomainListState (line 235) | class _DomainListState extends State<DomainList> {
method build (line 248) | Widget build(BuildContext context)
method rows (line 312) | List<Widget> rows(List<RegExp> list)
method remove (line 451) | Future<void> remove()
FILE: lib/ui/mobile/setting/hosts.dart
class HostsPage (line 31) | class HostsPage extends StatefulWidget {
method createState (line 37) | State<StatefulWidget> createState()
class _HostsPageState (line 40) | class _HostsPageState extends State<HostsPage> {
method initState (line 52) | void initState()
method build (line 66) | Widget build(BuildContext context)
method row (line 123) | Widget row(HostsItem item, bool isEven, {EdgeInsetsGeometry? padding})
method removeHosts (line 289) | Future<void> removeHosts(Set<HostsItem> items)
class FolderDialog (line 359) | class FolderDialog extends StatelessWidget {
method build (line 366) | Widget build(BuildContext context)
class HostsEditDialog (line 411) | class HostsEditDialog extends StatefulWidget {
method createState (line 418) | State<HostsEditDialog> createState()
class _HostsEditDialogState (line 421) | class _HostsEditDialogState extends State<HostsEditDialog> {
method initState (line 431) | void initState()
method dispose (line 441) | void dispose()
method build (line 448) | Widget build(BuildContext context)
FILE: lib/ui/mobile/setting/preference.dart
class Preference (line 15) | class Preference extends StatefulWidget {
method createState (line 22) | State<StatefulWidget> createState()
class _PreferenceState (line 25) | class _PreferenceState extends State<Preference> {
method initState (line 34) | void initState()
method dispose (line 46) | void dispose()
method build (line 52) | Widget build(BuildContext context)
method section (line 57) | Widget section(List<Widget> tiles)
method themeColor (line 156) | Widget themeColor(BuildContext context)
method _language (line 180) | void _language(BuildContext context)
method memoryCleanup (line 235) | Widget memoryCleanup(BuildContext context, AppLocalizations localizati...
class DropdownMenuInputItem (line 286) | class DropdownMenuInputItem extends DropdownMenuItem<int> {
FILE: lib/ui/mobile/setting/proxy.dart
class ExternalProxyDialog (line 10) | class ExternalProxyDialog extends StatefulWidget {
method createState (line 16) | State<StatefulWidget> createState()
class _ExternalProxyDialogState (line 21) | class _ExternalProxyDialogState extends State<ExternalProxyDialog> {
method initState (line 28) | void initState()
method build (line 37) | Widget build(BuildContext context)
FILE: lib/ui/mobile/setting/report_servers.dart
class ReportServersPageMobile (line 13) | class ReportServersPageMobile extends StatefulWidget {
method createState (line 17) | State<ReportServersPageMobile> createState()
class _ReportServersPageMobileState (line 20) | class _ReportServersPageMobileState extends State<ReportServersPageMobil...
method _openGuide (line 26) | Future<void> _openGuide()
method initState (line 42) | void initState()
method _load (line 47) | Future<void> _load()
method _showServerDialog (line 55) | Future<ReportServer?> _showServerDialog({ReportServer? initial})
method _addServer (line 66) | Future<void> _addServer()
method _editServer (line 75) | Future<void> _editServer(int index)
method _confirmDelete (line 85) | Future<void> _confirmDelete(int index)
method build (line 94) | Widget build(BuildContext context)
class ReportServerEditPageMobile (line 153) | class ReportServerEditPageMobile extends StatefulWidget {
method createState (line 159) | State<ReportServerEditPageMobile> createState()
class _ReportServerEditPageMobileState (line 162) | class _ReportServerEditPageMobileState extends State<ReportServerEditPag...
method initState (line 172) | void initState()
method dec (line 182) | InputDecoration dec({String? hint})
method labeled (line 192) | Widget labeled(String label, Widget field, {bool expanded = true})
method _onSave (line 200) | void _onSave()
method build (line 225) | Widget build(BuildContext context)
FILE: lib/ui/mobile/setting/request_block.dart
class MobileRequestBlock (line 7) | class MobileRequestBlock extends StatefulWidget {
method createState (line 13) | State<MobileRequestBlock> createState()
class _RequestBlockState (line 16) | class _RequestBlockState extends State<MobileRequestBlock> {
method build (line 20) | Widget build(BuildContext context)
method row (line 65) | Widget row(int index)
class RequestBlockAddDialog (line 159) | class RequestBlockAddDialog extends StatelessWidget {
method build (line 166) | Widget build(BuildContext context)
FILE: lib/ui/mobile/setting/request_breakpoint.dart
class MobileRequestBreakpointPage (line 16) | class MobileRequestBreakpointPage extends StatefulWidget {
method createState (line 22) | State<MobileRequestBreakpointPage> createState()
class _RequestBreakpointPageState (line 25) | class _RequestBreakpointPageState extends State<MobileRequestBreakpointP...
method _save (line 35) | Future<void> _save()
method initState (line 40) | void initState()
method dispose (line 47) | void dispose()
method build (line 52) | Widget build(BuildContext context)
method _buildList (line 102) | Widget _buildList()
method _buildRow (line 130) | Widget _buildRow(int index)
method _export (line 186) | Future<void> _export(RequestBreakpointManager? manager, {List<int>? in...
method _import (line 204) | Future<void> _import()
method _buildSelectionFooter (line 230) | Stack _buildSelectionFooter()
method _showRuleActions (line 277) | void _showRuleActions(int index)
method _removeRule (line 336) | Future<void> _removeRule(int index)
method _removeSelected (line 358) | Future<void> _removeSelected()
method _editRule (line 386) | void _editRule({RequestBreakpointRule? rule})
class MobileBreakpointRuleEditor (line 405) | class MobileBreakpointRuleEditor extends StatefulWidget {
method createState (line 411) | State<MobileBreakpointRuleEditor> createState()
class _MobileBreakpointRuleEditorState (line 414) | class _MobileBreakpointRuleEditorState extends State<MobileBreakpointRul...
method initState (line 429) | void initState()
method build (line 440) | Widget build(BuildContext context)
FILE: lib/ui/mobile/setting/request_crypto.dart
function _refreshConfig (line 17) | Future<void> _refreshConfig({bool force = false})
class MobileRequestCryptoPage (line 32) | class MobileRequestCryptoPage extends StatefulWidget {
method createState (line 36) | State<MobileRequestCryptoPage> createState()
class _MobileRequestCryptoPageState (line 39) | class _MobileRequestCryptoPageState extends State<MobileRequestCryptoPag...
method build (line 48) | Widget build(BuildContext context)
method _buildRuleList (line 107) | Widget _buildRuleList(RequestCryptoManager manager)
method _buildSelectionFooter (line 184) | Stack _buildSelectionFooter()
method _addRule (line 231) | Future<void> _addRule(RequestCryptoManager manager)
method _editRule (line 240) | Future<void> _editRule(RequestCryptoManager manager, int index)
method _showRuleActions (line 250) | void _showRuleActions(RequestCryptoManager manager, int index)
method _removeRule (line 310) | Future<void> _removeRule(RequestCryptoManager manager, int index)
method _removeSelected (line 318) | Future<void> _removeSelected()
method _import (line 338) | Future<void> _import(RequestCryptoManager manager)
method _export (line 360) | Future<void> _export(RequestCryptoManager manager, {List<int>? indexes})
class MobileCryptoRuleEditPage (line 381) | class MobileCryptoRuleEditPage extends StatefulWidget {
method createState (line 387) | State<MobileCryptoRuleEditPage> createState()
class _MobileCryptoRuleEditPageState (line 390) | class _MobileCryptoRuleEditPageState extends State<MobileCryptoRuleEditP...
method initState (line 416) | void initState()
method dispose (line 453) | void dispose()
method _decorate (line 462) | InputDecoration _decorate(String label, {String? hint})
method build (line 473) | Widget build(BuildContext context)
method _kvDropdown (line 657) | Widget _kvDropdown({required String label, required Widget child})
method _chipDropdown (line 676) | Widget _chipDropdown<T>({
method _ivPrefixLengthEditor (line 698) | Widget _ivPrefixLengthEditor()
method _save (line 727) | Future<void> _save()
FILE: lib/ui/mobile/setting/request_map.dart
function _refreshConfig (line 22) | void _refreshConfig({bool force = false})
class MobileRequestMapPage (line 33) | class MobileRequestMapPage extends StatefulWidget {
method createState (line 37) | State<StatefulWidget> createState()
class _RequestMapPageState (line 40) | class _RequestMapPageState extends State<MobileRequestMapPage> {
method initState (line 44) | void initState()
method dispose (line 49) | void dispose()
method build (line 54) | Widget build(BuildContext context)
method import (line 97) | Future<void> import()
method showEdit (line 127) | Future<void> showEdit()
class RequestMapList (line 137) | class RequestMapList extends StatefulWidget {
method createState (line 143) | State<RequestMapList> createState()
class _RequestMapListState (line 146) | class _RequestMapListState extends State<RequestMapList> {
method dispose (line 154) | void dispose()
method build (line 163) | Widget build(BuildContext context)
method rows (line 188) | List<Widget> rows(List<RequestMapRule> list)
method globalMenu (line 244) | Stack globalMenu()
method showMenus (line 287) | void showMenus(int index)
method showEdit (line 333) | Future<void> showEdit([int? index])
method export (line 351) | Future<void> export(List<int> indexes)
method enableStatus (line 380) | void enableStatus(bool enable)
method remove (line 388) | Future<void> remove(List<int> indexes)
class MobileRequestMapEdit (line 407) | class MobileRequestMapEdit extends StatefulWidget {
method createState (line 416) | State<StatefulWidget> createState()
class _RequestMapEditState (line 421) | class _RequestMapEditState extends State<MobileRequestMapEdit> {
method initState (line 435) | void initState()
method dispose (line 444) | void dispose()
method build (line 452) | Widget build(BuildContext context)
method onChangeType (line 550) | void onChangeType(RequestMapType? val)
method mapRule (line 556) | Widget mapRule()
method textField (line 564) | Widget textField(String label, TextEditingController controller, Strin...
method focusedBorder (line 587) | InputBorder focusedBorder()
FILE: lib/ui/mobile/setting/request_map/map_local.dart
class MobileMapLocal (line 31) | class MobileMapLocal extends StatefulWidget {
method createState (line 38) | State<MobileMapLocal> createState()
class MobileMapLocaleState (line 41) | class MobileMapLocaleState extends State<MobileMapLocal> {
method initItem (line 69) | void initItem(RequestMapItem? item)
method getRequestMapItem (line 81) | RequestMapItem getRequestMapItem()
method build (line 97) | Widget build(BuildContext context)
method tabBar (line 114) | TabBar tabBar(List<String> tabs)
method body (line 125) | Widget body()
method fileBodyEdit (line 164) | Widget fileBodyEdit()
method headers (line 199) | Widget headers()
method textField (line 203) | Widget textField(String label, dynamic value, String hint, {ValueChang...
method statusCodeEdit (line 222) | Widget statusCodeEdit()
method decoration (line 246) | InputDecoration decoration(String label, {String? hintText})
method focusedBorder (line 260) | InputBorder focusedBorder()
class Headers (line 266) | class Headers extends StatefulWidget {
method createState (line 272) | State<StatefulWidget> createState()
class HeadersState (line 277) | class HeadersState extends State<Headers> with AutomaticKeepAliveClientM...
method initState (line 286) | void initState()
method setHeaders (line 296) | void setHeaders(Map<String, String>? headers)
method getHeaders (line 305) | Map<String, String> getHeaders()
method _clear (line 322) | void _clear()
method build (line 331) | Widget build(BuildContext context)
method _buildRows (line 357) | List<Widget> _buildRows()
method _cell (line 378) | Widget _cell(TextEditingController val, {bool isKey = false})
method _row (line 394) | Widget _row(Widget key, Widget val, Widget? op)
FILE: lib/ui/mobile/setting/request_map/map_scipt.dart
class MobileMapScript (line 7) | class MobileMapScript extends StatefulWidget {
method createState (line 13) | State<MobileMapScript> createState()
class MobileMapScriptState (line 16) | class MobileMapScriptState extends State<MobileMapScript> {
method getScriptCode (line 37) | String getScriptCode()
method initState (line 42) | void initState()
method dispose (line 48) | void dispose()
method build (line 54) | Widget build(BuildContext context)
FILE: lib/ui/mobile/setting/request_rewrite.dart
class MobileRequestRewrite (line 39) | class MobileRequestRewrite extends StatefulWidget {
method createState (line 45) | State<MobileRequestRewrite> createState()
class _MobileRequestRewriteState (line 48) | class _MobileRequestRewriteState extends State<MobileRequestRewrite> {
method initState (line 52) | void initState()
method build (line 57) | Widget build(BuildContext context)
method import (line 93) | Future<void> import()
method add (line 122) | void add([int currentIndex = -1])
class RequestRuleList (line 132) | class RequestRuleList extends StatefulWidget {
method createState (line 138) | State<RequestRuleList> createState()
class _RequestRuleListState (line 141) | class _RequestRuleListState extends State<RequestRuleList> {
method dispose (line 157) | void dispose()
method build (line 166) | Widget build(BuildContext context)
method globalMenu (line 191) | Stack globalMenu()
method rows (line 233) | List<Widget> rows(List<RequestRewriteRule> list)
method showEdit (line 288) | Future<void> showEdit(int index)
method showMenus (line 303) | void showMenus(int index)
method export (line 360) | Future<void> export(BuildContext context, List<int> indexes)
method removeRewrite (line 384) | Future<void> removeRewrite()
class RewriteRule (line 404) | class RewriteRule extends StatefulWidget {
method createState (line 412) | State<StatefulWidget> createState()
class _RewriteRuleState (line 417) | class _RewriteRuleState extends State<RewriteRule> {
method initState (line 432) | void initState()
method dispose (line 447) | void dispose()
method build (line 455) | Widget build(BuildContext context)
method onChangeType (line 586) | void onChangeType(RuleType? val)
method fromRequestItems (line 604) | List<RewriteItem> fromRequestItems(HttpRequest request, RuleType ruleT...
method rewriteRule (line 615) | Widget rewriteRule()
method textField (line 624) | Widget textField(String label, TextEditingController controller, Strin...
FILE: lib/ui/mobile/setting/rewrite/rewrite_replace.dart
class MobileRewriteReplace (line 29) | class MobileRewriteReplace extends StatefulWidget {
method createState (line 37) | State<MobileRewriteReplace> createState()
class RewriteReplaceState (line 40) | class RewriteReplaceState extends State<MobileRewriteReplace> {
method initItems (line 65) | void initItems(RuleType ruleType, List<RewriteItem>? items)
method _initRewriteItem (line 88) | void _initRewriteItem(List<RewriteItem>? items, RewriteType type, {boo...
method getItems (line 103) | List<RewriteItem> getItems()
method build (line 115) | Widget build(BuildContext context)
method tabBar (line 143) | TabBar tabBar(List<String> tabs)
method body (line 160) | Widget body()
method fileBodyEdit (line 228) | Widget fileBodyEdit(RewriteItem item)
method headers (line 262) | Widget headers()
method requestLine (line 287) | Widget requestLine()
method redirectEdit (line 337) | Widget redirectEdit(RewriteItem rewriteItem)
method textField (line 351) | Widget textField(String label, dynamic value, String hint, {ValueChang...
method statusCodeEdit (line 369) | Widget statusCodeEdit()
method decoration (line 405) | InputDecoration decoration(String label, {String? hintText})
method focusedBorder (line 417) | InputBorder focusedBorder()
class Headers (line 423) | class Headers extends StatefulWidget {
method createState (line 430) | State<StatefulWidget> createState()
class HeadersState (line 435) | class HeadersState extends State<Headers> with AutomaticKeepAliveClientM...
method initState (line 444) | void initState()
method setHeaders (line 453) | void setHeaders(Map<String, String>? headers)
method getHeaders (line 461) | Map<String, String> getHeaders()
method build (line 487) | Widget build(BuildContext context)
method _buildRows (line 512) | List<Widget> _buildRows()
method _cell (line 533) | Widget _cell(TextEditingController val, {bool isKey = false})
method _row (line 548) | Widget _row(Widget key, Widget val, Widget? op)
FILE: lib/ui/mobile/setting/rewrite/rewrite_update.dart
class MobileRewriteUpdate (line 26) | class MobileRewriteUpdate extends StatefulWidget {
method createState (line 34) | State<MobileRewriteUpdate> createState()
class RewriteUpdateState (line 37) | class RewriteUpdateState extends State<MobileRewriteUpdate> {
method initState (line 44) | void initState()
method getItems (line 61) | List<RewriteItem> getItems()
method build (line 66) | Widget build(BuildContext context)
class RewriteUpdateEdit (line 101) | class RewriteUpdateEdit extends StatefulWidget {
method createState (line 109) | State<RewriteUpdateEdit> createState()
class _RewriteUpdateAddState (line 112) | class _RewriteUpdateAddState extends State<RewriteUpdateEdit> {
method initState (line 126) | void initState()
method dispose (line 140) | void dispose()
method build (line 148) | Widget build(BuildContext context)
method textField (line 321) | Widget textField(String label, String hint, {bool required = false, in...
method formField (line 328) | Widget formField(String hint, {bool required = false, int? lines, Text...
method focusedBorder (line 347) | InputBorder focusedBorder()
class UpdateList (line 352) | class UpdateList extends StatefulWidget {
method createState (line 360) | State<UpdateList> createState()
class _UpdateListState (line 363) | class _UpdateListState extends State<UpdateList> {
method initState (line 367) | void initState()
method build (line 372) | Widget build(BuildContext context)
method rows (line 393) | List<Widget> rows(List<RewriteItem> list)
method getText (line 441) | String getText(RewriteItem item)
FILE: lib/ui/mobile/setting/script.dart
class MobileScript (line 42) | class MobileScript extends StatefulWidget {
method createState (line 46) | State<StatefulWidget> createState()
function _refreshScript (line 52) | void _refreshScript({bool force = false})
class _MobileScriptState (line 63) | class _MobileScriptState extends State<MobileScript> {
method build (line 67) | Widget build(BuildContext context)
method consoleLog (line 117) | void consoleLog()
method import (line 123) | Future<void> import()
method scriptEdit (line 157) | Future<void> scriptEdit()
class ScriptConsoleLog (line 167) | class ScriptConsoleLog extends StatefulWidget {
method createState (line 171) | State<StatefulWidget> createState()
class _ScriptConsoleLogState (line 174) | class _ScriptConsoleLogState extends State<ScriptConsoleLog> {
method initState (line 185) | void initState()
method dispose (line 213) | void dispose()
method build (line 223) | Widget build(BuildContext context)
method loggerContent (line 258) | Widget loggerContent()
class ScriptLogSmallWindow (line 286) | class ScriptLogSmallWindow extends StatefulWidget {
method createState (line 292) | State<StatefulWidget> createState()
class _ScriptLogSmallWindowState (line 295) | class _ScriptLogSmallWindowState extends State<ScriptLogSmallWindow> {
method initState (line 300) | void initState()
method dispose (line 317) | void dispose()
method build (line 325) | Widget build(BuildContext context)
method list (line 359) | Widget list()
class ScriptEdit (line 382) | class ScriptEdit extends StatefulWidget {
method createState (line 401) | State<StatefulWidget> createState()
class _ScriptEditState (line 404) | class _ScriptEditState extends State<ScriptEdit> {
method initState (line 415) | void initState()
method dispose (line 430) | void dispose()
method _fetchRemoteScript (line 441) | Future<void> _fetchRemoteScript()
method _resetScript (line 477) | void _resetScript()
method build (line 482) | Widget build(BuildContext context)
method textField (line 759) | Widget textField(String label, TextEditingController controller, Strin...
method focusedBorder (line 779) | InputBorder focusedBorder()
class ScriptList (line 785) | class ScriptList extends StatefulWidget {
method createState (line 791) | State<ScriptList> createState()
class _ScriptListState (line 794) | class _ScriptListState extends State<ScriptList> {
method build (line 801) | Widget build(BuildContext context)
method globalMenu (line 823) | Stack globalMenu()
method rows (line 865) | List<Widget> rows(List<ScriptItem> list)
method showMenus (line 924) | void showMenus(int index)
method showEdit (line 984) | Future<void> showEdit([int? index])
method export (line 1008) | Future<void> export(BuildContext context, List<int> indexes)
method enableStatus (line 1033) | void enableStatus(bool enable)
method removeScripts (line 1041) | Future<void> removeScripts(List<int> indexes)
FILE: lib/ui/mobile/setting/ssl.dart
class MobileSslWidget (line 37) | class MobileSslWidget extends StatefulWidget {
method createState (line 43) | State<MobileSslWidget> createState()
class _MobileSslState (line 46) | class _MobileSslState extends State<MobileSslWidget> {
method initState (line 56) | void initState()
method _refreshStatus (line 63) | Future<void> _refreshStatus()
method dispose (line 84) | void dispose()
method build (line 89) | Widget build(BuildContext context)
method section (line 94) | Widget section(List<Widget> tiles)
method importPk12 (line 189) | void importPk12()
method exportP12 (line 233) | void exportP12()
method _exportFile (line 267) | void _exportFile(String name, {File? file, Uint8List? bytes})
class AndroidCaInstall (line 280) | class AndroidCaInstall extends StatefulWidget {
method createState (line 284) | State<StatefulWidget> createState()
class _AndroidCaInstallState (line 287) | class _AndroidCaInstallState extends State<AndroidCaInstall> with Single...
method initState (line 293) | void initState()
method dispose (line 299) | void dispose()
method build (line 305) | Widget build(BuildContext context)
method rootCA (line 320) | ListView rootCA()
method userCA (line 367) | ListView userCA()
method _downloadCert (line 399) | void _downloadCert(String name)
method _autoInstallCert (line 410) | Future<void> _autoInstallCert()
method _getAndroidVersion (line 456) | Future<String?> _getAndroidVersion()
function evaluateChainTrusted (line 469) | Future<bool> evaluateChainTrusted(String caPem)
class IOSCertChecker (line 475) | class IOSCertChecker {
method check (line 478) | void check(BuildContext context)
class CertStatusCard (line 533) | class CertStatusCard extends StatelessWidget {
method build (line 548) | Widget build(BuildContext context)
class IosCaInstall (line 591) | class IosCaInstall extends StatefulWidget {
method createState (line 597) | State<IosCaInstall> createState()
class _IosCaInstallState (line 600) | class _IosCaInstallState extends State<IosCaInstall> {
method initState (line 609) | void initState()
method _refreshStatus (line 614) | Future<void> _refreshStatus()
method _downloadCert (line 637) | void _downloadCert()
method _copyProxyLink (line 645) | void _copyProxyLink()
method build (line 658) | Widget build(BuildContext context)
method _statusCard (line 678) | Widget _statusCard(bool isCN)
method _certDetails (line 732) | Widget _certDetails(X509CertificateData details)
method _kv (line 746) | Widget _kv(String k, String v, TextStyle? ks, TextStyle? vs)
method _guideSection (line 761) | Widget _guideSection(bool isCN)
FILE: lib/ui/mobile/setting/theme.dart
class MobileThemeSetting (line 20) | class MobileThemeSetting extends StatelessWidget {
method build (line 26) | Widget build(BuildContext context)
method getIcon (line 67) | Icon getIcon()
FILE: lib/ui/mobile/widgets/about.dart
class About (line 25) | class About extends StatefulWidget {
method createState (line 29) | State<StatefulWidget> createState()
class _AboutState (line 34) | class _AboutState extends State<About> {
method build (line 38) | Widget build(BuildContext context)
method _safeLaunch (line 128) | Future<void> _safeLaunch(Uri uri)
method _showSponsorDialog (line 132) | void _showSponsorDialog(AppLocalizations l10n, String sponsorUrl)
FILE: lib/ui/mobile/widgets/floating_window.dart
class FloatingWindowManager (line 4) | class FloatingWindowManager {
method show (line 16) | void show(BuildContext context, {required Widget widget})
method hide (line 27) | void hide()
class FloatingWindow (line 33) | class FloatingWindow extends StatefulWidget {
method createState (line 46) | State<FloatingWindow> createState()
class _FloatingWindowState (line 49) | class _FloatingWindowState extends State<FloatingWindow> with TickerProv...
method changeState (line 62) | void changeState()
method initState (line 67) | void initState()
method build (line 80) | Widget build(BuildContext context)
method getValue (line 108) | double getValue(double value, double max)
method getWidgetSize (line 118) | Size getWidgetSize(GlobalKey key)
FILE: lib/ui/mobile/widgets/highlight.dart
class KeywordHighlight (line 23) | class KeywordHighlight extends StatefulWidget {
method createState (line 27) | State<KeywordHighlight> createState()
class _KeywordHighlightState (line 30) | class _KeywordHighlightState extends State<KeywordHighlight> {
method build (line 34) | Widget build(BuildContext context)
method decoration (line 81) | InputDecoration decoration(String label, {String? hintText})
method dispose (line 91) | void dispose()
FILE: lib/ui/mobile/widgets/pip.dart
class PictureInPictureWindow (line 29) | class PictureInPictureWindow extends StatefulWidget {
method createState (line 35) | State<PictureInPictureWindow> createState()
class _PictureInPictureWindowState (line 38) | class _PictureInPictureWindowState extends State<PictureInPictureWindow> {
method initState (line 44) | void initState()
method dispose (line 53) | void dispose()
method build (line 59) | Widget build(BuildContext context)
class PictureInPictureIcon (line 81) | class PictureInPictureIcon extends StatefulWidget {
method createState (line 90) | State<PictureInPictureIcon> createState()
class _PictureInPictureState (line 93) | class _PictureInPictureState extends State<PictureInPictureIcon> {
method initState (line 103) | void initState()
method build (line 112) | Widget build(BuildContext context)
FILE: lib/ui/mobile/widgets/remote_device.dart
class RemoteModel (line 43) | class RemoteModel {
method copyWith (line 70) | RemoteModel copyWith({
method equals (line 91) | bool equals(RemoteModel remoteModel)
method toJson (line 95) | Map<String, dynamic> toJson()
class RemoteDevicePage (line 100) | class RemoteDevicePage extends StatefulWidget {
method createState (line 107) | State<RemoteDevicePage> createState()
class _RemoteDevicePageState (line 110) | class _RemoteDevicePageState extends State<RemoteDevicePage> {
method build (line 116) | Widget build(BuildContext context)
method rows (line 185) | Widget rows(SharedPreferences prefs)
method getIcon (line 212) | Icon getIcon(String os)
method getRemoteDeviceList (line 226) | List<RemoteModel> getRemoteDeviceList(SharedPreferences prefs)
method setRemoteDeviceList (line 231) | Future<bool> setRemoteDeviceList(SharedPreferences prefs, Iterable<Rem...
method remoteDeviceStatus (line 237) | Widget remoteDeviceStatus()
method doConnect (line 399) | Future<bool> doConnect(String host, int port, {bool? ipProxy})
class ConfigSyncWidget (line 506) | class ConfigSyncWidget extends StatefulWidget {
method createState (line 513) | State<StatefulWidget> createState()
class ConfigSyncState (line 518) | class ConfigSyncState extends State<ConfigSyncWidget> {
method build (line 527) | Widget build(BuildContext context)
FILE: lib/ui/toolbox/aes_page.dart
class AesPage (line 12) | class AesPage extends StatefulWidget {
method createState (line 16) | State<AesPage> createState()
class _AesWidgetState (line 19) | class _AesWidgetState extends State<AesPage> {
method encryptText (line 32) | void encryptText()
method decryptText (line 48) | void decryptText()
method build (line 68) | Widget build(BuildContext context)
FILE: lib/ui/toolbox/cert_hash.dart
class CertHashPage (line 32) | class CertHashPage extends StatefulWidget {
method createState (line 38) | State<StatefulWidget> createState()
class _CertHashPageState (line 43) | class _CertHashPageState extends State<CertHashPage> {
method initState (line 50) | void initState()
method dispose (line 58) | void dispose()
method onKeyEvent (line 65) | bool onKeyEvent(KeyEvent event)
method build (line 78) | Widget build(BuildContext context)
method tryDerFormat (line 154) | String? tryDerFormat(Uint8List data)
FILE: lib/ui/toolbox/encoder.dart
type EncoderType (line 12) | enum EncoderType {
class EncoderWidget (line 28) | class EncoderWidget extends StatefulWidget {
method createState (line 36) | State<EncoderWidget> createState()
class _EncoderState (line 39) | class _EncoderState extends State<EncoderWidget> with SingleTickerProvid...
method initState (line 56) | void initState()
method dispose (line 66) | void dispose()
method onKeyEvent (line 72) | bool onKeyEvent(KeyEvent event)
method build (line 85) | Widget build(BuildContext context)
method encode (line 149) | void encode()
method decode (line 169) | void decode()
method encodeToUnicode (line 198) | String encodeToUnicode(String input)
method decodeFromUnicode (line 202) | String decodeFromUnicode(String input)
FILE: lib/ui/toolbox/js_run.dart
class JavaScript (line 17) | class JavaScript extends StatefulWidget {
method createState (line 23) | State<StatefulWidget> createState()
class _JavaScriptState (line 28) | class _JavaScriptState extends State<JavaScript> {
method initState (line 44) | void initState()
method dispose (line 60) | void dispose()
method consoleLog (line 71) | dynamic consoleLog(dynamic args)
Condensed preview — 435 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,721K chars).
[
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 638,
"preview": "name: Bug report\ndescription: Create reports to help us improve\nlabels: bug\nbody:\n - type: dropdown\n attributes:\n "
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yml",
"chars": 935,
"preview": "name: Feature request\ndescription: Suggest an idea for this project\nlabels: enhancement\nbody:\n - type: dropdown\n att"
},
{
"path": ".github/ISSUE_TEMPLATE/功能请求.yml",
"chars": 702,
"preview": "name: 功能请求\ndescription: 为这个项目提出一个想法\nlabels: enhancement\nbody:\n - type: dropdown\n attributes:\n label: Operating "
},
{
"path": ".gitignore",
"chars": 767,
"preview": "# Miscellaneous\n*.class\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.build/\n.buildlog/\n.history\n.svn/\n.swiftpm/\nmigrate_working_d"
},
{
"path": ".metadata",
"chars": 926,
"preview": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrade"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 2741,
"preview": "# ProxyPin\n\nEnglish | [中文](README_CN.md)\n## Open source free traffic capture HTTP(S),Support Windows、Mac、Android、IOS、Lin"
},
{
"path": "README_CN.md",
"chars": 1311,
"preview": "# ProxyPin\n\n[English](README.md) | 中文\n## 开源免费抓包工具,支持Windows、Mac、Android、IOS、Linux 全平台系统\n\n您可以使用它来拦截、检查和重写HTTP(S)流量,支持Flut"
},
{
"path": "analysis_options.yaml",
"chars": 1099,
"preview": "# The following line activates a set of recommended lints for Flutter apps,\n# packages, and plugins designed to encourag"
},
{
"path": "android/.gitignore",
"chars": 295,
"preview": "gradle-wrapper.jar\n/.gradle\n/captures/\n/gradlew\n/gradlew.bat\n/local.properties\nGeneratedPluginRegistrant.java\n\n# Remembe"
},
{
"path": "android/app/build.gradle",
"chars": 3468,
"preview": "import java.util.Properties\nimport java.io.FileInputStream\nimport java.io.File\n\nplugins {\n id \"com.android.applicatio"
},
{
"path": "android/app/proguard-rules.pro",
"chars": 338,
"preview": "#Flutter Wrapper\n-keep class io.flutter.app.** { *; }\n-keep class io.flutter.plugin.** { *; }\n-keep class io.flutter.ut"
},
{
"path": "android/app/src/debug/AndroidManifest.xml",
"chars": 378,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <!-- The INTERNET permission is required for d"
},
{
"path": "android/app/src/main/AndroidManifest.xml",
"chars": 3896,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tools=\"http://schemas.android.com/tools\">"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/MainActivity.kt",
"chars": 2337,
"preview": "package com.network.proxy\n\nimport android.content.Intent\nimport android.content.res.Configuration\nimport com.network.pro"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/ProxyVpnService.kt",
"chars": 13316,
"preview": "package com.network.proxy\n\nimport android.app.Activity\nimport android.app.Notification\nimport android.app.NotificationCh"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/VpnAlertDialog.kt",
"chars": 616,
"preview": "package com.network.proxy\n\nimport android.app.Activity\nimport android.app.AlertDialog\nimport android.os.Bundle\nimport ko"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/plugin/AndroidFlutterPlugin.kt",
"chars": 889,
"preview": "package com.network.proxy.plugin\n\nimport android.app.Activity\nimport io.flutter.embedding.engine.plugins.FlutterPlugin\ni"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/plugin/AppInfo.kt",
"chars": 2657,
"preview": "package com.network.proxy.plugin\n\nimport android.content.pm.ApplicationInfo\nimport android.content.pm.PackageManager\nimp"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/plugin/AppLifecyclePlugin.kt",
"chars": 732,
"preview": "package com.network.proxy.plugin\n\nimport io.flutter.embedding.engine.plugins.FlutterPlugin\nimport io.flutter.plugin.comm"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/plugin/InstalledAppsPlugin.kt",
"chars": 3376,
"preview": "package com.network.proxy.plugin\n\nimport android.content.pm.ApplicationInfo\nimport io.flutter.embedding.engine.plugins.F"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/plugin/PictureInPicturePlugin.kt",
"chars": 6374,
"preview": "package com.network.proxy.plugin\n\nimport android.app.PendingIntent\nimport android.app.PictureInPictureParams\nimport andr"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/plugin/ProcessInfoPlugin.kt",
"chars": 2084,
"preview": "package com.network.proxy.plugin\n\nimport com.network.proxy.vpn.util.ProcessInfoManager\nimport io.flutter.embedding.engin"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/plugin/VpnServicePlugin.kt",
"chars": 3465,
"preview": "package com.network.proxy.plugin\n\nimport com.network.proxy.ProxyVpnService\nimport io.flutter.embedding.engine.plugins.Fl"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/Connection.kt",
"chars": 5031,
"preview": "package com.network.proxy.vpn\n\nimport android.util.Log\nimport com.network.proxy.vpn.socket.CloseableConnection\nimport co"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/ConnectionHandler.kt",
"chars": 25079,
"preview": "package com.network.proxy.vpn\n\nimport android.util.Log\nimport com.network.proxy.vpn.Connection.Companion.getConnectionKe"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/ConnectionManager.kt",
"chars": 5562,
"preview": "package com.network.proxy.vpn\n\nimport android.os.Build\nimport android.util.Log\nimport com.network.proxy.vpn.socket.Close"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/Protocol.java",
"chars": 74,
"preview": "package com.network.proxy.vpn;\n\npublic enum Protocol {\n TCP,\n UDP\n}\n"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/ProxyVpnThread.kt",
"chars": 3388,
"preview": "package com.network.proxy.vpn\n\nimport android.os.ParcelFileDescriptor\nimport android.util.Log\nimport com.network.proxy.P"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/Tag.kt",
"chars": 155,
"preview": "package com.network.proxy.vpn\n\n\nfun formatTag(tag: String): String {\n return tag\n}\n\nval Any.TAG: String\n get() {\n "
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/socket/ClientPacketWriter.kt",
"chars": 1492,
"preview": "package com.network.proxy.vpn.socket\n\nimport android.util.Log\nimport java.io.FileOutputStream\nimport java.io.IOException"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/socket/CloseableConnection.kt",
"chars": 188,
"preview": "package com.network.proxy.vpn.socket\n\nimport com.network.proxy.vpn.Connection\n\ninterface CloseableConnection {\n /**\n "
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/socket/Constant.kt",
"chars": 103,
"preview": "package com.network.proxy.vpn.socket\n\nobject Constant {\n const val MAX_RECEIVE_BUFFER_SIZE = 65535\n}"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/socket/ProtectSocket.kt",
"chars": 296,
"preview": "package com.network.proxy.vpn.socket\n\nimport java.net.DatagramSocket\nimport java.net.Socket\n\ninterface ProtectSocket {\n\n"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/socket/ProtectSocketHolder.kt",
"chars": 727,
"preview": "package com.network.proxy.vpn.socket\n\nimport java.net.DatagramSocket\nimport java.net.Socket\n\n/**\n * ProtectSocket的持有者,用于"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/socket/SocketChannelReader.java",
"chars": 8007,
"preview": "package com.network.proxy.vpn.socket;\n\nimport androidx.annotation.NonNull;\n\nimport android.util.Log;\n\nimport com.network"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/socket/SocketChannelWriter.java",
"chars": 4652,
"preview": "package com.network.proxy.vpn.socket;\n\nimport androidx.annotation.NonNull;\nimport android.util.Log;\n\n\nimport com.network"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/socket/SocketNIODataService.java",
"chars": 7444,
"preview": "package com.network.proxy.vpn.socket;\n\nimport android.util.Log;\n\n\nimport com.network.proxy.vpn.Connection;\nimport com.ne"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/transport/Packet.kt",
"chars": 266,
"preview": "package com.network.proxy.vpn.transport\n\nimport com.network.proxy.vpn.transport.protocol.IP4Header\nimport com.network.pr"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/transport/icmp/ICMPPacket.java",
"chars": 1428,
"preview": "package com.network.proxy.vpn.transport.icmp;\n\n\nimport androidx.annotation.NonNull;\n\npublic class ICMPPacket {\n // Tw"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/transport/icmp/ICMPPacketFactory.java",
"chars": 2710,
"preview": "package com.network.proxy.vpn.transport.icmp;\n\n\nimport androidx.annotation.NonNull;\n\nimport com.network.proxy.vpn.transp"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/transport/protocol/IP4Header.kt",
"chars": 4916,
"preview": "package com.network.proxy.vpn.transport.protocol\n\nimport android.util.Log\nimport java.nio.ByteBuffer\nimport java.nio.Byt"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/transport/protocol/TCPHeader.kt",
"chars": 5466,
"preview": "package com.network.proxy.vpn.transport.protocol\n\nimport java.nio.ByteBuffer\nimport java.nio.ByteOrder\n\n/**\n * TCP报头的数据结"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/transport/protocol/TCPPacketFactory.kt",
"chars": 8349,
"preview": "package com.network.proxy.vpn.transport.protocol\n\nimport com.network.proxy.vpn.transport.Packet\nimport com.network.proxy"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/transport/protocol/TransportHeader.kt",
"chars": 142,
"preview": "package com.network.proxy.vpn.transport.protocol\n\ninterface TransportHeader {\n fun getSourcePort(): Int\n fun getDe"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/transport/protocol/UDPHeader.kt",
"chars": 3014,
"preview": "package com.network.proxy.vpn.transport.protocol\n\n\nimport com.network.proxy.vpn.util.PacketUtil\nimport java.nio.ByteBuff"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/util/PacketUtil.kt",
"chars": 9217,
"preview": "package com.network.proxy.vpn.util\n\nimport android.util.Log\nimport com.network.proxy.vpn.formatTag\nimport com.network.pr"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/util/ProcessInfoManager.kt",
"chars": 7872,
"preview": "package com.network.proxy.vpn.util\n\nimport android.content.Context\nimport android.net.ConnectivityManager\nimport android"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/util/SimpleCache.kt",
"chars": 1739,
"preview": "package com.network.proxy.vpn.util\n\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.concurrent.Executors\n"
},
{
"path": "android/app/src/main/kotlin/com/network/proxy/vpn/util/TLS.kt",
"chars": 2900,
"preview": "package com.network.proxy.vpn.util\n\nimport java.nio.ByteBuffer\nimport kotlin.math.min\n\n\nobject TLS {\n\n /**\n * 判断是"
},
{
"path": "android/app/src/main/res/drawable/launch_background.xml",
"chars": 434,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmln"
},
{
"path": "android/app/src/main/res/drawable-v21/launch_background.xml",
"chars": 438,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmln"
},
{
"path": "android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
"chars": 328,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <bac"
},
{
"path": "android/app/src/main/res/values/styles.xml",
"chars": 1139,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <!-- Theme applied to the Android Window while the process is sta"
},
{
"path": "android/app/src/main/res/values-night/styles.xml",
"chars": 995,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <!-- Theme applied to the Android Window while the process is sta"
},
{
"path": "android/app/src/profile/AndroidManifest.xml",
"chars": 378,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <!-- The INTERNET permission is required for d"
},
{
"path": "android/build.gradle",
"chars": 1680,
"preview": "allprojects {\n repositories {\n google()\n mavenCentral()\n }\n\n subprojects {\n afterEvaluate "
},
{
"path": "android/gradle/wrapper/gradle-wrapper.properties",
"chars": 233,
"preview": "#Tue Nov 28 00:35:45 CST 2023\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://"
},
{
"path": "android/gradle.properties",
"chars": 108,
"preview": "org.gradle.jvmargs=-Xmx4G\nandroid.useAndroidX=true\nandroid.enableJetifier=true\nandroid.nonFinalResIds=false\n"
},
{
"path": "android/settings.gradle",
"chars": 819,
"preview": "import java.util.Properties\n\npluginManagement {\n def flutterSdkPath = {\n def properties = new Properties()\n "
},
{
"path": "assets/certs/ca.crt",
"chars": 1407,
"preview": "-----BEGIN CERTIFICATE-----\nMIID4jCCAsqgAwIBAgIJAKcH8Dna4mnZMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV\nBAYTAkNOMQswCQYDVQQIDAJCSjE"
},
{
"path": "assets/certs/ca_key.pem",
"chars": 1704,
"preview": "-----BEGIN CERTIFICATE-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDEY3xbxQ2Uvj7H\nXnVDatCp+be0RTUtIkK2QC6+CyZ"
},
{
"path": "assets/js/fetch.js",
"chars": 2493,
"preview": "function fetch(url, options) {\n options = options || {};\n return new Promise((resolve, reject) => {\n const "
},
{
"path": "devtools_options.yaml",
"chars": 184,
"preview": "description: This file stores settings for Dart & Flutter DevTools.\ndocumentation: https://docs.flutter.dev/tools/devtoo"
},
{
"path": "distribute_options.yaml",
"chars": 522,
"preview": "output: dist/\n\nreleases:\n - name: release\n jobs:\n - name: macos-dmg\n package:\n platform: macos\n"
},
{
"path": "ios/.gitignore",
"chars": 569,
"preview": "**/dgph\n*.mode1v3\n*.mode2v3\n*.moved-aside\n*.pbxuser\n*.perspectivev3\n**/*sync/\n.sconsign.dblite\n.tags*\n**/.vagrant/\n**/De"
},
{
"path": "ios/Flutter/AppFrameworkInfo.plist",
"chars": 774,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Flutter/Debug.xcconfig",
"chars": 107,
"preview": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig\"\n#include \"Generated.xcconfig\"\n"
},
{
"path": "ios/Flutter/Release.xcconfig",
"chars": 109,
"preview": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig\"\n#include \"Generated.xcconfig\"\n"
},
{
"path": "ios/Podfile",
"chars": 2028,
"preview": "# Uncomment this line to define a global platform for your project\nplatform :ios, '13.0'\n\n# CocoaPods analytics sends ne"
},
{
"path": "ios/ProxyPin/Info.plist",
"chars": 431,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/ProxyPin/PacketTunnelProvider.swift",
"chars": 4830,
"preview": "//\n// PacketTunnelProvider.swift\n// ProxyPin\n//\n// Created by 汪红恩 on 2023/7/4.\n//\n\nimport NetworkExtension\nimport Net"
},
{
"path": "ios/ProxyPin/ProxyPin-Bridging-Header.h",
"chars": 111,
"preview": "//\n// ProxyPin-Bridging-Header.h\n// Runner\n//\n// Created by wanghongen on 2025/5/28.\n//\n\n#import \"GBPing.h\"\n"
},
{
"path": "ios/ProxyPin/ProxyPin.entitlements",
"chars": 562,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/ProxyPin/vpn/Connection.swift",
"chars": 3192,
"preview": "//\n// Connection.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/17.\n//\n\nimport Foundation\n\n\nimport Foundatio"
},
{
"path": "ios/ProxyPin/vpn/ConnectionHandler.swift",
"chars": 20677,
"preview": "//\n// ConnectionHandler.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/16.\n//\n\nimport Foundation\nimport Netw"
},
{
"path": "ios/ProxyPin/vpn/ConnectionManager.swift",
"chars": 4792,
"preview": "//\n// ConnectionManager.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/16.\n//\n\nimport Foundation\nimport Netw"
},
{
"path": "ios/ProxyPin/vpn/NWProtocol.swift",
"chars": 148,
"preview": "//\n// NWProtocol.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/17.\n//\n\nimport Foundation\n\n\npublic enum NWPr"
},
{
"path": "ios/ProxyPin/vpn/ProxyVpnService.swift",
"chars": 1575,
"preview": "//\n// ProxyService.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/17.\n//\n\nimport Foundation\nimport NetworkEx"
},
{
"path": "ios/ProxyPin/vpn/QueueFactory.swift",
"chars": 482,
"preview": "//\n// QueueFactory.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/17.\n//\n\nimport Foundation\n\nclass QueueFact"
},
{
"path": "ios/ProxyPin/vpn/ping/GBPing.h",
"chars": 1864,
"preview": "//\n// GBPing.h\n// GBPing\n//\n// Created by Luka Mirosevic on 05/11/2012.\n// Copyright (c) 2012 Goonbee. All rights re"
},
{
"path": "ios/ProxyPin/vpn/ping/GBPing.m",
"chars": 32929,
"preview": "//\n// GBPing.m\n// GBPing\n//\n// Created by Luka Mirosevic on 05/11/2012.\n// Copyright (c) 2012 Goonbee. All rights re"
},
{
"path": "ios/ProxyPin/vpn/ping/GBPingHelper.swift",
"chars": 2291,
"preview": "//\n// GBPingHelper.swift\n//\n\nimport Foundation\n\npublic typealias Handler = ((_ response: [String: Any]) -> Void)\n\npubli"
},
{
"path": "ios/ProxyPin/vpn/ping/GBPingSummary.h",
"chars": 889,
"preview": "//\n// GBPingSummary.h\n// GBPing\n//\n// Created by Luka Mirosevic on 05/11/2012.\n// Copyright (c) 2012 Goonbee. All ri"
},
{
"path": "ios/ProxyPin/vpn/ping/GBPingSummary.m",
"chars": 1532,
"preview": "//\n// GBPingSummary.m\n// GBPing\n//\n// Created by Luka Mirosevic on 05/11/2012.\n// Copyright (c) 2012 Goonbee. All ri"
},
{
"path": "ios/ProxyPin/vpn/ping/ICMPHeader.h",
"chars": 2271,
"preview": "//\n// ICMPHeader.h\n// GBPing\n//\n// Created by Luka Mirosevic on 15/11/2012.\n// Copyright (c) 2012 Goonbee. All right"
},
{
"path": "ios/ProxyPin/vpn/socket/ClientPacketWriter.swift",
"chars": 522,
"preview": "//\n// ClientPacketWriter.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/\n\nimport Foundation\nimport NetworkEx"
},
{
"path": "ios/ProxyPin/vpn/socket/CloseableConnection.swift",
"chars": 225,
"preview": "//\n// CloseableConnection.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/17.\n//\n\nimport Foundation\n\n\nprotoco"
},
{
"path": "ios/ProxyPin/vpn/socket/SocketIOService.swift",
"chars": 8700,
"preview": "//\n// ProxySocketIOService.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/17.\n//\n\nimport Foundation\nimport N"
},
{
"path": "ios/ProxyPin/vpn/transport/Packet.swift",
"chars": 403,
"preview": "//\n// Packet.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/17.\n//\n\nimport Foundation\n\n\nclass Packet {\n v"
},
{
"path": "ios/ProxyPin/vpn/transport/protocol/ICMPPacket.swift",
"chars": 3442,
"preview": "//\n// ICMPPacket.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/10/3.\n//\n\nimport Foundation\n\nclass ICMPPacket "
},
{
"path": "ios/ProxyPin/vpn/transport/protocol/IP4Header.swift",
"chars": 6816,
"preview": "//\n// IP4Header.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/16.\n//\n\nimport Foundation\nimport os.log\n\n// I"
},
{
"path": "ios/ProxyPin/vpn/transport/protocol/TCPHeader.swift",
"chars": 5098,
"preview": "//\n// TCPHeader.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/16.\n//\n\nimport Foundation\n\n/// Represents a T"
},
{
"path": "ios/ProxyPin/vpn/transport/protocol/TCPPacketFactory.swift",
"chars": 10354,
"preview": "//\n// TCPPacketFactory.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/16.\n//\n//\n\nimport Foundation\nimport os"
},
{
"path": "ios/ProxyPin/vpn/transport/protocol/TransportHeader.swift",
"chars": 206,
"preview": "//\n// TransportHeader.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/17.\n//\n\nimport Foundation\n\nprotocol Tra"
},
{
"path": "ios/ProxyPin/vpn/transport/protocol/UDPHeader.swift",
"chars": 3223,
"preview": "//\n// UDPHeader.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/17.\n//\n\nimport Foundation\nimport os.log\n\n///U"
},
{
"path": "ios/ProxyPin/vpn/utils/PacketUtil.swift",
"chars": 3767,
"preview": "//\n// PacketUtil.swift\n// ProxyPin\n//\n// Created by wanghongen on 2024/9/17.\n//\n\nimport Foundation\nimport os.log\n\ncla"
},
{
"path": "ios/ProxyPin/vpn/utils/TLS.swift",
"chars": 1202,
"preview": "//\n// TLS.swift\n// Runner\n//\n// Created by wanghongen on 2025/5/31.\n//\n\nclass TLS {\n \n static func isTLSClientH"
},
{
"path": "ios/Runner/AppDelegate.swift",
"chars": 4851,
"preview": "import UIKit\nimport Flutter\nimport NetworkExtension\n\n@main\n@objc class AppDelegate: FlutterAppDelegate {\n \n var ba"
},
{
"path": "ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1838,
"preview": "{\n \"images\": [\n {\n \"filename\": \"AppIcon@2x.png\",\n \"idiom\": \"iphone\",\n \"scale\": \"2x\",\n \"size\": \"6"
},
{
"path": "ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
"chars": 391,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"LaunchImage.png\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
"chars": 336,
"preview": "# Launch Screen Assets\n\nYou can customize the launch screen with your own desired assets by replacing the image files in"
},
{
"path": "ios/Runner/AudioManager.swift",
"chars": 5794,
"preview": "import Foundation\nimport AVFoundation\nimport UIKit\nclass AudioManager: NSObject {\n \n static let shared = AudioMana"
},
{
"path": "ios/Runner/Base.lproj/LaunchScreen.storyboard",
"chars": 2377,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "ios/Runner/Base.lproj/Main.storyboard",
"chars": 1605,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "ios/Runner/Handlers/MethodHandler.swift",
"chars": 7756,
"preview": "//\n// MethodHandler.swift\n// Runner\n//\n// Created by wanghongen on 2025/5/30.\n//\n\nimport Flutter\nimport Network\nimpor"
},
{
"path": "ios/Runner/Info.plist",
"chars": 2444,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner/Runner-Bridging-Header.h",
"chars": 38,
"preview": "#import \"GeneratedPluginRegistrant.h\"\n"
},
{
"path": "ios/Runner/Runner.entitlements",
"chars": 684,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner/VpnManager.swift",
"chars": 6288,
"preview": "let kProxyServiceVPNStatusNotification = \"kProxyServiceVPNStatusNotification\"\n\nimport Foundation\nimport NetworkExtension"
},
{
"path": "ios/Runner/en.lproj/InfoPlist.strings",
"chars": 169,
"preview": "\"NSCameraUsageDescription\"=\"Scan QR code\";\n\"NSPhotoLibraryUsageDescription\"=\"Access to Photo Library\";\n\"PhotoLibraryAddU"
},
{
"path": "ios/Runner/pip/PictureInPictureManager.swift",
"chars": 6770,
"preview": "//\n// PictureInPicturePlugin.swift\n// Runner\n//\n// Created by wanghongen on 2024/1/8.\n//\n\nimport AVKit\nimport UIKit\ni"
},
{
"path": "ios/Runner/pip/PictureInPictureView.swift",
"chars": 2180,
"preview": "//\n// PictureInPictureView.swift\n// Runner\n//\n// Created by wanghongen on 2024/1/9.\n//\n\nimport SwiftUI\n\n@available(iO"
},
{
"path": "ios/Runner/zh-Hans.lproj/InfoPlist.strings",
"chars": 123,
"preview": "\"NSCameraUsageDescription\"=\"扫描二维码\";\n\"NSPhotoLibraryUsageDescription\"=\"访问相册\";\n\"PhotoLibraryAddUsageDescription\"= \"保存图片到相册"
},
{
"path": "ios/Runner/zh-Hans.lproj/LaunchScreen.strings",
"chars": 1,
"preview": "\n"
},
{
"path": "ios/Runner/zh-Hans.lproj/Main.strings",
"chars": 1,
"preview": "\n"
},
{
"path": "ios/Runner.xcodeproj/project.pbxproj",
"chars": 57121,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 135,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:\">\n </FileRef"
},
{
"path": "ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"chars": 226,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
"chars": 3833,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1510\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "ios/Runner.xcworkspace/contents.xcworkspacedata",
"chars": 224,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:Runner.xcodepr"
},
{
"path": "ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"chars": 226,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/RunnerTests/RunnerTests.swift",
"chars": 285,
"preview": "import Flutter\nimport UIKit\nimport XCTest\n\nclass RunnerTests: XCTestCase {\n\n func testExample() {\n // If you add cod"
},
{
"path": "l10n.yaml",
"chars": 166,
"preview": "#synthetic-package: false\narb-dir: lib/l10n\ntemplate-arb-file: app_en.arb\noutput-localization-file: app_localizations.da"
},
{
"path": "lib/l10n/app_en.arb",
"chars": 15446,
"preview": "{\n \"breakpoint\": \"Breakpoint\",\n \"breakpointRule\": \"Breakpoint Rule\",\n \"name\": \"Name\",\n \"requests\": \"Requests\",\n \"fa"
},
{
"path": "lib/l10n/app_localizations.dart",
"chars": 60278,
"preview": "import 'dart:async';\n\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/widgets.dart';\nimport 'package:f"
},
{
"path": "lib/l10n/app_localizations_en.dart",
"chars": 24358,
"preview": "// ignore: unused_import\nimport 'package:intl/intl.dart' as intl;\nimport 'app_localizations.dart';\n\n// ignore_for_file: "
},
{
"path": "lib/l10n/app_localizations_zh.dart",
"chars": 37962,
"preview": "// ignore: unused_import\nimport 'package:intl/intl.dart' as intl;\nimport 'app_localizations.dart';\n\n// ignore_for_file: "
},
{
"path": "lib/l10n/app_zh.arb",
"chars": 10188,
"preview": "{\n\n \"breakpoint\": \"断点\",\n \"breakpointRule\": \"断点规则\",\n \"name\": \"名称\",\n \"requests\": \"抓包\",\n \"favorites\": \"收藏\",\n \"history"
},
{
"path": "lib/l10n/app_zh_Hant.arb",
"chars": 10200,
"preview": "{\n \"breakpoint\": \"斷點\",\n \"breakpointRule\": \"斷點規則\",\n \"requests\": \"抓包\",\n \"favorites\": \"收藏\",\n \"history\": \"歷史\",\n \"toolb"
},
{
"path": "lib/main.dart",
"chars": 4868,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/native/app_lifecycle.dart",
"chars": 1660,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:proxypin/network/util/lo"
},
{
"path": "lib/native/installed_apps.dart",
"chars": 1782,
"preview": "import 'package:flutter/services.dart';\n\nclass InstalledApps {\n static const MethodChannel _methodChannel = MethodChann"
},
{
"path": "lib/native/native_method.dart",
"chars": 1549,
"preview": "import 'package:flutter/services.dart';\nimport 'package:proxypin/network/util/logger.dart';\n\nclass NativeMethod {\n stat"
},
{
"path": "lib/native/pip.dart",
"chars": 1754,
"preview": "import 'dart:io';\n\nimport 'package:flutter/services.dart';\nimport 'package:proxypin/native/vpn.dart';\nimport 'package:pr"
},
{
"path": "lib/native/process_info.dart",
"chars": 1128,
"preview": "import 'dart:io';\n\nimport 'package:flutter/services.dart';\nimport 'package:proxypin/network/channel/host_port.dart';\nimp"
},
{
"path": "lib/native/vpn.dart",
"chars": 1989,
"preview": "import 'package:flutter/services.dart';\nimport 'package:proxypin/network/bin/configuration.dart';\nimport 'package:proxyp"
},
{
"path": "lib/network/bin/configuration.dart",
"chars": 4579,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/bin/listener.dart",
"chars": 1155,
"preview": "import 'package:proxypin/network/channel/channel.dart';\nimport 'package:proxypin/network/channel/channel_context.dart';\n"
},
{
"path": "lib/network/bin/server.dart",
"chars": 4559,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/channel/channel.dart",
"chars": 5274,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/channel/channel_context.dart",
"chars": 3514,
"preview": "import 'package:proxypin/network/channel/channel.dart';\nimport 'package:proxypin/network/channel/host_port.dart';\nimport"
},
{
"path": "lib/network/channel/channel_dispatcher.dart",
"chars": 10902,
"preview": "import 'dart:async';\nimport 'dart:typed_data';\n\nimport 'package:proxypin/network/channel/channel.dart';\nimport 'package:"
},
{
"path": "lib/network/channel/host_port.dart",
"chars": 5799,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/channel/network.dart",
"chars": 10943,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/host_filter.dart",
"chars": 2325,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/hosts.dart",
"chars": 1399,
"preview": "/*\n * Copyright 2024 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/interceptor.dart",
"chars": 960,
"preview": "import 'package:proxypin/network/channel/host_port.dart';\nimport 'package:proxypin/network/http/http.dart';\n\n/// A Inter"
},
{
"path": "lib/network/components/js/file.dart",
"chars": 7071,
"preview": "/*\n * Copyright 2024 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/js/md5.dart",
"chars": 1538,
"preview": "/*\n * Copyright 2024 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/js/script_engine.dart",
"chars": 4827,
"preview": "import 'dart:convert';\nimport 'dart:io';\n\nimport 'package:flutter_js/flutter_js.dart';\nimport 'package:proxypin/network/"
},
{
"path": "lib/network/components/js/xhr.dart",
"chars": 15305,
"preview": "import 'dart:async';\nimport 'dart:convert';\nimport 'dart:io';\n\nimport 'package:desktop_multi_window/desktop_multi_window"
},
{
"path": "lib/network/components/manager/hosts_manager.dart",
"chars": 5091,
"preview": "/*\n * Copyright 2024 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/manager/report_server_manager.dart",
"chars": 3701,
"preview": "import 'dart:convert';\n\nimport '../../../storage/path.dart';\nimport '../../util/logger.dart';\n\nclass ReportServerManager"
},
{
"path": "lib/network/components/manager/request_block_manager.dart",
"chars": 3411,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/manager/request_breakpoint_manager.dart",
"chars": 3493,
"preview": "import 'dart:convert';\nimport 'dart:io';\n\nimport 'package:desktop_multi_window/desktop_multi_window.dart';\nimport 'packa"
},
{
"path": "lib/network/components/manager/request_crypto_manager.dart",
"chars": 6992,
"preview": "import 'dart:convert';\nimport 'dart:io';\n\nimport 'package:proxypin/network/http/http.dart';\nimport 'package:proxypin/net"
},
{
"path": "lib/network/components/manager/request_map_manager.dart",
"chars": 6193,
"preview": "import 'dart:convert';\nimport 'dart:io';\n\nimport 'package:desktop_multi_window/desktop_multi_window.dart';\nimport 'packa"
},
{
"path": "lib/network/components/manager/request_rewrite_manager.dart",
"chars": 7069,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/manager/rewrite_rule.dart",
"chars": 7072,
"preview": "/*\n * Copyright 2024 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/manager/script_manager.dart",
"chars": 12766,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/report_server_interceptor.dart",
"chars": 3990,
"preview": "/*\n * Copyright 2024 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/request_block.dart",
"chars": 1699,
"preview": "/*\n * Copyright 2024 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/request_breakpoint.dart",
"chars": 4089,
"preview": "import 'dart:async';\n\nimport 'package:proxypin/network/components/interceptor.dart';\nimport 'package:proxypin/network/co"
},
{
"path": "lib/network/components/request_map.dart",
"chars": 4111,
"preview": "/*\n * Copyright 2025 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/request_rewrite.dart",
"chars": 10193,
"preview": "/*\n * Copyright 2024 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/components/script.dart",
"chars": 1901,
"preview": "/*\n * Copyright 2024 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/handle/http_proxy_handle.dart",
"chars": 11269,
"preview": "import 'dart:convert';\n\nimport 'package:proxypin/network/bin/listener.dart';\nimport 'package:proxypin/network/channel/ch"
},
{
"path": "lib/network/handle/relay_handle.dart",
"chars": 531,
"preview": "import 'package:proxypin/network/channel/channel.dart';\nimport 'package:proxypin/network/channel/channel_context.dart';\n"
},
{
"path": "lib/network/handle/sse_handle.dart",
"chars": 1432,
"preview": "import 'dart:typed_data';\n\nimport 'package:proxypin/network/channel/channel.dart';\nimport 'package:proxypin/network/chan"
},
{
"path": "lib/network/handle/websocket_handle.dart",
"chars": 1240,
"preview": "import 'dart:typed_data';\n\nimport 'package:proxypin/network/channel/channel.dart';\nimport 'package:proxypin/network/chan"
},
{
"path": "lib/network/http/codec.dart",
"chars": 8497,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/http/constants.dart",
"chars": 365,
"preview": "class HttpConstants {\n //h2协议\n static const String h2 = 'h2';\n static const String h2_14 = 'h2-14';\n\n /// Line feed "
},
{
"path": "lib/network/http/content_type.dart",
"chars": 5881,
"preview": "/*\n * Copyright Copyright 2024 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (th"
},
{
"path": "lib/network/http/h2/frame.dart",
"chars": 2855,
"preview": "/*\n * Copyright 2023 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\""
},
{
"path": "lib/network/http/h2/h2_codec.dart",
"chars": 21152,
"preview": "/*\n * Copyright 2023 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\""
},
{
"path": "lib/network/http/h2/hpack/hpack.dart",
"chars": 11500,
"preview": "// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file\n// for details. All rights reserved. Use o"
},
{
"path": "lib/network/http/h2/hpack/huffman.dart",
"chars": 4670,
"preview": "// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file\n// for details. All rights reserved. Use o"
},
{
"path": "lib/network/http/h2/hpack/huffman_table.dart",
"chars": 9888,
"preview": "// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file\n// for details. All rights reserved. Use o"
},
{
"path": "lib/network/http/h2/setting.dart",
"chars": 2964,
"preview": "/*\n * Copyright 2023 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\""
},
{
"path": "lib/network/http/http.dart",
"chars": 13327,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/http/http_client.dart",
"chars": 10265,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/http/http_headers.dart",
"chars": 7451,
"preview": "// ignore_for_file: constant_identifier_names\n\n/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed unde"
},
{
"path": "lib/network/http/parse/body_reader.dart",
"chars": 4111,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/http/parse/http_parser.dart",
"chars": 2734,
"preview": "import 'dart:typed_data';\n\nimport 'package:proxypin/network/http/constants.dart';\nimport 'package:proxypin/network/http/"
},
{
"path": "lib/network/http/sse.dart",
"chars": 3361,
"preview": "/*\n * Server-Sent Events (text/event-stream) incremental decoder\n */\n\nimport 'dart:convert';\nimport 'dart:typed_data';\n\n"
},
{
"path": "lib/network/http/websocket.dart",
"chars": 6615,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/socks/socks5.dart",
"chars": 5258,
"preview": "/*\n * Copyright 2024 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/util/attribute_keys.dart",
"chars": 420,
"preview": "/// @author wanghongen\n/// 2023/5/23\ninterface class AttributeKeys {\n static const String host = \"HOST\";\n static const"
},
{
"path": "lib/network/util/byte_buf.dart",
"chars": 3223,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/util/byte_utils.dart",
"chars": 1503,
"preview": "import 'dart:typed_data';\n\nList<int> viewOrSublist(List<int> data, int offset, int length) {\n if (data is Uint8List) {\n"
},
{
"path": "lib/network/util/cache.dart",
"chars": 2792,
"preview": "/*\n * Copyright 2023 Hongen Wang All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
},
{
"path": "lib/network/util/cert/basic_constraints.dart",
"chars": 227,
"preview": "/// @author wanghongen\n/// 2024/7/28\nclass BasicConstraints {\n final bool isCA;\n final int? pathLenConstraint;\n final"
},
{
"path": "lib/network/util/cert/cert_data.dart",
"chars": 6012,
"preview": "import 'dart:typed_data';\n\nimport 'extension.dart';\nimport 'key_usage.dart';\n\nclass X509CertificateData {\n /// The subj"
},
{
"path": "lib/network/util/cert/der.dart",
"chars": 11042,
"preview": "import 'dart:typed_data';\nimport 'dart:convert';\nimport 'package:proxypin/network/util/byte_buf.dart';\nimport 'package:p"
},
{
"path": "lib/network/util/cert/extension.dart",
"chars": 954,
"preview": "import 'package:pointycastle/pointycastle.dart';\n\n/// an object for the elements in the X.509 V3 extension block.\nclass "
},
{
"path": "lib/network/util/cert/key_usage.dart",
"chars": 1492,
"preview": "import 'dart:typed_data';\n\nimport 'package:pointycastle/pointycastle.dart';\n\nenum KeyUsage {\n /// 0\n DIGITAL_SIGNATURE"
},
{
"path": "lib/network/util/cert/pkcs12.dart",
"chars": 26672,
"preview": "import 'dart:typed_data';\n\nimport 'package:pointycastle/asn1.dart';\nimport 'package:pointycastle/export.dart';\n\nimport '"
}
]
// ... and 235 more files (download for full content)
About this extraction
This page contains the full source code of the wanghongenpin/proxypin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 435 files (2.5 MB), approximately 671.2k tokens, and a symbol index with 2796 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.