Mitm.js

repository·master·Indexed 20 days ago

https://github.com/moll/node-mitm

A Node.js library for intercepting and mocking outgoing TCP and HTTP/HTTPS network connections in-process. It allows developers to assert on request parameters and mock server responses by providing access to Net.Socket, Http.IncomingMessage, and Http.ServerResponse objects. It features the ability to bypass interception for specific connections and uses monkey-patching of Node.js core modules (net, tls, http, https) to enable interception.

Tokens
2.4K
Snippets
11
Records
13
Agent score
71%

What's inside mitm

  1. Best practice: Intercepting in tests

    master

    When using Mitm.js in a testing framework, use beforeEach and afterEach hooks to ensure interception is enabled only for the duration of each test case and is properly cleaned up afterward.

    beforeEach(function() { this.mitm = Mitm() })
    afterEach(function() { this.mitm.disable() })
  2. Bypass interception for specific connections

    master

    To allow certain connections (like database connections or localhost integration tests) to reach the real network, listen for the connect event and call .bypass() on the provided socket. The connect event provides an opts object containing the original connection parameters (e.g., host and port).

    mitm.on("connect", function(socket, opts) {
      if (opts.host == "sql.example.org" && opts.port == 5432) {
        socket.bypass()
      }
    })
  3. Initialize and use Mitm.js

    master

    To start intercepting, require the module and invoke it as a function. This creates a Mitm instance and immediately enables interception for all subsequent network requests. To stop intercepting, call the .disable() method on the instance.

    var Mitm = require("mitm")
    var mitm = Mitm()
    
    // ... intercepting happens here ...
    
    mitm.disable()
  4. How Mitm intercepts network traffic

    master

    Mitm works by using a Stubs utility to monkey-patch Node.js core networking methods.

    1. Stubbing: When .enable() is called, Mitm replaces net.connect, net.createConnection, Http.Agent.prototype.createConnection, and tls.connect with its own internal handlers.
    2. Socket Pairing: When a connection is attempted, Mitm creates a pair of InternalSocket instances. One represents the client (the application making the request) and the other represents the server (the destination being simulated).
    3. Bypassing: If a socket is marked as bypassed, Mitm will call the original underlying method instead of intercepting it.
    4. HTTP Detection: For TCP/TLS connections, Mitm uses ClientRequest.prototype.onSocket to hook into HTTP requests. Once a request is detected, it uses Node's internal _connectionListener to create the IncomingMessage and ServerResponse objects.
  5. Initialize and enable Mitm

    master

    To start intercepting network traffic, instantiate Mitm and call .enable(). The Mitm constructor can be called with new Mitm() or as a function Mitm(). Calling .enable() performs the necessary monkey-patching of Node.js core modules (net, tls, http, https) to intercept connections. To stop interception and restore original behavior, call .disable().

    Note that Mitm is an EventEmitter, so you can listen for events like connect, connection, and request immediately after instantiation.

    ```javascript
    const Mitm = require('mitm');
    const mitm = new Mitm().enable();
    
    // To stop intercepting:
    // mitm.disable();
    ```埋
  6. Intercept HTTP/HTTPS requests

    master

    Mitm.js intercepts Http.request and Https.request calls and emits a request event. The event listener receives a server-side Http.IncomingMessage (req) and Http.ServerResponse (res).

    Note: HTTPS requests are currently morphed into HTTP requests to avoid certificate management.

    Note: Custom HTTP methods are not supported out-of-the-box because the underlying Node.js HTTP parser throws errors for unsupported methods.

    // Asserting on a request
    mitm.on("request", function(req, res) {
      req.headers.authorization.must.equal("OAuth DEADBEEF")
    })
    
    Http.get("http://example.org")
    
    // Responding to a request
    mitm.on("request", function(req, res) {
      res.statusCode = 402
      res.end("Pay up, sugar!")
    })
    
    Http.get("http://example.org", function(res) {
      res.setEncoding("utf8")
      res.statusCode // => 402
      res.on("data", console.log) // => "Pay up, sugar!"
    })
  7. Intercept TCP socket connections

    master

    Mitm.js intercepts Net.connect calls and emits a connection event. The event listener receives a server-side Net.Socket object, allowing you to respond to the client as if you were the remote server.

    mitm.on("connection", function(socket) {
      socket.write("Hello back!")
    })
    
    var socket = Net.connect(22, "example.org")
    socket.write("Hello!")
    socket.setEncoding("utf8")
    socket.on("data", console.log) // => "Hello back!"
  8. Reference: Mitm.js Events

    master

    The following events are emitted by a Mitm instance:

    EventDescription
    connectEmitted when a TCP connection is made. Given the client side Net.Socket and options from Net.connect.
    connectionEmitted when a TCP connection is made. Given the server side Net.Socket and options from Net.connect.
    requestEmitted when a HTTP/HTTPS request is made. Given the server side Http.IncomingMessage and Http.ServerResponse.
  9. Stub and restore object properties with Stubs

    master

    The Stubs class provides a mechanism to temporarily replace properties on an object and restore their original values later. This is useful for mocking or intercepting behavior during tests.

    • Use .stub(obj, prop, value) to replace obj[prop] with value. The original value is tracked internally.
    • Use .restore() to revert all stubbed properties back to their original state in reverse order of stubbing.
    const Stubs = require('./lib/stubs');
    const stubs = new Stubs();
    
    const myObj = { key: 'original' };
    
    // Replace 'key' with 'mocked'
    stubs.stub(myObj, 'key', 'mocked');
    console.log(myObj.key); // 'mocked'
    
    // Revert to 'original'
    stubs.restore();
    console.log(myObj.key); // 'original'
  10. Intercept TCP and TLS connections with Mitm

    master

    When Mitm is enabled, it intercepts calls to net.connect, net.createConnection, and tls.connect.

    • TCP Interception: Emits a connect event on the client socket and a connection event on the server socket.
    • TLS Interception: Emits a secureConnect event on the client socket.

    Events emitted:

    • connect: Emitted on the client-side socket. Arguments: (client, opts).
    • connection: Emitted on the server-side socket. Arguments: (server, opts).
    • secureConnect: Emitted on the client-side TLS socket.
    const Mitm = require('mitm');
    const mitm = new Mitm().enable();
    
    mitm.on('connect', (client, opts) => {
      console.log('TCP connection intercepted:', opts);
    });
    
    mitm.on('connection', (server, opts) => {
      console.log('Server-side socket created:', opts);
    });
  11. Intercept HTTP/HTTPS requests with Mitm

    master

    When an intercepted connection is identified as an HTTP request, Mitm triggers the request event. This event provides access to both the IncomingMessage (request) and ServerResponse (response) objects.

    Mitm automatically cross-references the request and response objects, meaning req.res points to the response and res.req points to the request.

    Events emitted:

    • request: Emitted when an HTTP request is detected. Arguments: (req, res).
    const Mitm = require('mitm');
    const mitm = new Mitm().enable();
    
    mitm.on('request', (req, res) => {
      console.log('Intercepted request:', req.method, req.url);
      
      // Cross-references are available:
      // req.res === res
      // res.req === req
    
      res.end('Intercepted!');
    });