ProxyPin

repository·main·Indexed 9 days ago

https://github.com/wanghongenpin/proxypin

An open-source, cross-platform HTTP(S) traffic capture and inspection tool for Windows, Mac, Android, iOS, and Linux. It allows developers to intercept, inspect, and rewrite network traffic, with specialized support for Flutter app traffic. Key features include SSL/HTTPS packet capture, SOCKS5 proxy support, system proxy integration, and a flexible environment variable management system using {{name}} syntax for dynamic string replacement.

Tokens
11.8K
Snippets
49
Records
57
Agent score
95%

What's inside ProxyPin

  1. Overview of ProxyPin features

    main

    ProxyPin is an open-source, free HTTP(S) traffic capture tool that supports Windows, Mac, Android, iOS, and Linux. It is built with Flutter and is designed to intercept, inspect, and rewrite HTTP(S) traffic, including traffic from Flutter applications.

    Core Capabilities:

    • Mobile QR Code Connection: Connect devices via QR code scanning to avoid manual Wi-Fi proxy configuration and synchronization.
    • Domain Filtering: Intercept only specific traffic to avoid interference from other applications.
    • Search: Search requests using keywords and various response type conditions.
    • Scripting: Use JavaScript to process requests or responses.
    • Request Rewriting: Supports redirection, replacing request/response bodies, or modifying them based on specific rules.
    • Request Mapping: Use local configurations or scripts to respond to requests instead of hitting remote services.
    • Request Decryption: Automatically decrypt HTTP message bodies by configuring AES decryption keys.
    • Request Blocking: Block requests based on URL to prevent them from reaching the server.
    • History & Export: Automatically saves traffic data for review. Supports importing and exporting in HAR format.
    • Utilities: Includes favorites, a toolbox, common encoding tools, QR code generation, and regex support.
  2. Install ProxyPin on macOS

    main

    When opening ProxyPin on macOS for the first time, you may see a prompt stating the developer is untrusted. To allow the application to run, you must manually authorize it in your system settings:

    1. Open System Preferences.
    2. Navigate to Security & Privacy.
    3. Select Allow any source.
  3. Customize the iOS launch screen assets

    main

    To change the launch screen image for the iOS version of the application, you can use one of two methods:

    1. Direct File Replacement: Replace the existing image files located in the ios/Runner/Assets.xcassets/LaunchImage.imageset/ directory with your own assets.
    2. Xcode Interface:
      • Open the iOS project in Xcode using the command: open ios/Runner.xcworkspace.
      • In the Project Navigator, navigate to Runner/Assets.xcassets.
      • Drag and drop your desired images into the asset catalog to replace the current launch images.
    open ios/Runner.xcworkspace
  4. Manage SSL/TLS certificates with CertificateManager

    main

    The CertificateManager class provides a centralized way to handle CA (Certificate Authority) roots, generate leaf certificates for specific hosts, and manage security contexts for HTTPS interception. It maintains an internal cache of SecurityContext objects to optimize performance.

    Key capabilities include:

    • Automatic CA Initialization: Loading the root CA and private key from the application support directory.
    • Leaf Certificate Generation: Creating self-signed certificates for specific domains to allow traffic interception.
    • Remote Certificate Mimicry: Regenerating leaf certificates based on real remote server certificates to bypass strict client-side validation (e.g., matching Subject, SAN, and validity periods).
    • PKCS#12 Support: Exporting and importing certificates via .p12 files.
    import 'package:proxypin/network/util/crts.dart';
    
    // Example: Get a security context for a specific host
    SecurityContext? context = CertificateManager.get('www.example.com');
    
    // Example: Get or initialize a context for a host
    SecurityContext context = await CertificateManager.getCertificateContext('www.example.com');
  5. Simulate network conditions with NetworkConditionInterceptor

    main

    The NetworkConditionInterceptor is used to inject network impairments into the HTTP request/response lifecycle. It allows you to simulate real-world scenarios such as high latency, packet loss, offline states, and bandwidth throttling (upload/download speeds).

    Key Behaviors

    • Offline Mode: If the resolved condition is set to offline, the interceptor returns null, preventing the request from being sent and simulating a connection failure.
    • Packet Loss: If lossRate is configured, the interceptor may randomly discard the entire request/response, returning a synthesized 502 status code with the header X-ProxyPin-Weak-Network: loss to simulate connection timeouts or failures.
    • Latency & Jitter: Applies a base latency (requestLatencyMs or responseLatencyMs) plus a random jitterMs to the request or response.
    • Bandwidth Throttling: Calculates additional delay based on the body size and the configured uploadKbps (for requests) or downloadKbps (for responses). The formula used is (bytes * 8 / kbps) to convert kilobits per second to milliseconds.

    Lifecycle Integration

    • onRequest: Applies request latency, jitter, and upload throttling.
    • onResponse: Applies response latency, jitter, and download throttling.
    • execute: Handles the short-circuiting logic for offline and lossRate scenarios.

    Note: The interceptor has a priority of 1100, ensuring it runs after standard blocking interceptors (which typically have a priority of 1000).

    import 'package:proxypin/network/components/network_condition.dart';
    
    // Access the singleton instance
    final interceptor = NetworkConditionInterceptor.instance;
  6. Resolve and render variables using {{name}} syntax

    main

    ProxyPin supports dynamic string replacement using the {{name}} syntax. This is useful for injecting environment variables into rewrite rules or scripts.

    • Syntax: {{variable_name}}. The name can contain alphanumeric characters, underscores, dots, or hyphens. Whitespace inside the braces is allowed (e.g., {{ name }}).
    • Resolution Logic: The manager attempts to find the variable in the active environment first, then the global environment. If the variable is not found or the manager is disabled, the original {{name}} token is preserved in the output.
    • Non-recursive: Rendering only performs a single pass; it does not recursively resolve variables within resolved values.
    • Performance: For high-frequency paths (like interceptors), use EnvironmentManager.tryRender(input) to avoid unnecessary overhead if the manager isn't loaded or the input doesn't contain {{.
    // Example of variable rendering
    // If 'api_host' is 'https://api.example.com' in the active environment:
    String result = EnvironmentManager.tryRender('http://{{ api_host }}/v1') ?? '';
    // result == 'http://https://api.example.com/v1'
    
    // If 'missing_var' is not defined:
    String result2 = EnvironmentManager.tryRender('{{ missing_var }}') ?? '';
    // result2 == '{{ missing_var }}'
  7. Manage environments with EnvironmentManager

    main

    The EnvironmentManager is a singleton used to manage sets of environment variables. It supports a mandatory Global environment (which cannot be deleted) and multiple user-defined named environments (e.g., Dev, Staging, Prod).

    Key behaviors:

    • Global Environment: Always exists. Variables defined here act as fallbacks.
    • Active Environment: Only one named environment can be active at a time via activeId. When an environment is active, its variables take precedence over Global variables.
    • Variable Resolution: When resolving a variable name, the manager first looks in the active environment, then falls back to the global environment.
    • Persistence: Configuration is stored in environments.json in the user's home directory.
    // Accessing the singleton instance
    final manager = await EnvironmentManager.instance;
    
    // Setting the active environment
    manager.setActive('some-env-id');
    
    // Accessing the global environment
    final globalEnv = manager.global;
    
    // Accessing the currently active environment
    final activeEnv = manager.active;
  8. How the Configuration singleton works

    main

    The Configuration class is implemented as a singleton to ensure a single source of truth for proxy settings throughout the application lifecycle.

    • Initialization: The instance getter is asynchronous. It first checks if an instance exists; if not, it attempts to load the configuration from the local config.cnf file using _loadConfig() and parses it via fromJson().
    • Error Handling: If loading the configuration fails (e.g., due to a malformed JSON file), the error is logged, and a new Configuration instance with default values is returned to prevent application crashes.
    • Persistence: The toJson() method maps all internal properties, including the HostFilter lists, into a format suitable for JSON serialization, which is then written to disk by flushConfig().
  9. Configure network conditions via NetworkConditionManager

    main

    To control the behavior of the NetworkConditionInterceptor, you must use the NetworkConditionManager. The interceptor calls NetworkConditionManager.resolve(requestUrl) to fetch the specific configuration for a given URL.

    Configuration Resolution

    • URL-Specific Rules: You can define specific network conditions for individual URLs.
    • Fallback Mechanism: If a specific rule for a URL is not found, the system falls back to global default settings.
    • Parameter Snapshot: The resolve method provides a snapshot of the effective parameters (latency, loss rate, bandwidth, etc.) for that specific request, allowing for granular control (e.g., configuring different timeouts for different endpoints).
  10. Initialize ProxyPin application

    main

    The application entrypoint main(List<String> args) handles platform-specific initialization, including Rust FFI via RustLib.init(), environment preloading via EnvironmentManager.preload(), and window management for desktop platforms. It supports a multi_window mode via command-line arguments to initialize secondary windows.

    void main(List<String> args) async {
      WidgetsFlutterBinding.ensureInitialized();
      try {
        await RustLib.init();
      } catch (e) {
        print('RustLib.init failed: $e');
      }
      // ... platform specific logic
    }
  11. Troubleshooting Mac installation: Unverified Developer error

    main

    When opening ProxyPin on macOS for the first time, you may see a warning that the developer is untrusted. To resolve this:

    1. Open System Preferences.
    2. Navigate to Security & Privacy.
    3. Under the General tab, select Allow apps downloaded from: Anywhere.