Skip to content

Tool to inspect SQLite databases and intercept network requests from mobile applications.

License

Notifications You must be signed in to change notification settings

pakerwreah/Inspector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

2792ecc · Sep 11, 2022
Sep 11, 2022
Sep 11, 2022
Sep 8, 2022
Apr 19, 2021
Aug 8, 2021
Aug 8, 2021
Sep 9, 2022
Apr 6, 2020
Aug 8, 2021
May 18, 2021
Sep 6, 2020
May 18, 2021
Nov 3, 2020

Repository files navigation

Inspector

release c++ android ios codecov ci ci ci

Tool to inspect SQLite databases and intercept network requests from mobile applications.

Project targeting Android, iOS and Web using C/C++, Java, Objective-C, Vue.js, WebSocket, SQLite and IndexedDB. The data is shown in a web interface and uses WebSocket to communicate directly with the app via local network. To keep network log history the web system uses the built-in IndexedDB from the browser.

Frontend repository

https://github.com/pakerwreah/InspectorWeb

Android

Version

Setup

Gradle

repositories {
    maven { url "https://jitpack.io" }
}
dependencies {
    implementation "com.github.pakerwreah:Inspector:<release-tag>"
}

Proguard

-keep class br.newm.inspector.* { *; }
Usage

Application

import br.newm.inspector.Inspector;

public class Application extends android.app.Application {
    @Override
    public void onCreate() {
        super.onCreate();

        Inspector.initializeWith(this);

        // SQLCipher support
        // database name, password, sqlcipher major version
        Inspector.setCipherKey("database_cipher3.db", "123456", 3);
        Inspector.setCipherKey("database_cipher4.db", "123456", 4);
    }

    // Optional: if you want to specify databases names to show
    @Override
    public String[] databaseList() {
        return new String[]{"database.db", "database_cipher3.db", "database_cipher4.db"};
    }
}

Intercept network requests

⚠️ if you use addNetworkInterceptor it won't intercept timeouts

import br.newm.inspector.NetworkInterceptor;

new OkHttpClient.Builder().addInterceptor(new NetworkInterceptor());

Static plugins

Accepts returning JSON, HTML or plain text

Inspector.addPlugin("prefs", "Shared Preferences", new PluginAction() {
    @Override
    public String action() {
        return new JSONObject(prefs.getAll()).toString();
    }
});

Live plugins

Accepts complex HTML frontend with javascript support
Check ExplorerPlugin.java for a full example

Inspector.addLivePlugin("explorer", "Explorer", new PluginAction() {
    @Override
    public String action() {
        // return plugin frontend
    }
});

Plugin API

Route with parameters to be used as a plugin or standalone api
Check ExplorerPlugin.java for a full example

Inspector.addPluginAPI("GET", "filesystem/list", new PluginAPIAction() {
    @Override
    public String action(Map<String, String> params) {
        // return json array with list of files
    }
});

Inspector.addPluginAPI("GET", "filesystem/open", new PluginAPIActionBinary() {
    @Override
    public byte[] action(Map<String, String> params) {
        // return file contents
    }
});

Websockets

Send messages to your live plugins

new WebSocket(`ws://${location.hostname}:${location.port}/plugins/ws/mykey`)
Inspector.sendMessage("mykey", "Hello world!");

⚠️ You should run this command to work with emulators

# same port number used to initialize the plugin
adb forward tcp:30000 tcp:30000

Or configure its network as bridge and use the device's IP

iOS

Version

Setup

CocoaPods

target 'MyApp' do
   pod "IOSInspector"
end
Usage

AppDelegate

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, IOSInspectorProtocol {

    func applicationDidFinishLaunching(_ application: UIApplication) {

        IOSInspector.initialize(withDelegate: self)

        // SQLCipher support
        IOSInspector.setCipherKey("database_cipher3.db", password: "123456", version: 3)
        IOSInspector.setCipherKey("database_cipher4.db", password: "123456", version: 4)
    }

    // Required: specify databases paths
    func databaseList() -> [String] {
        let documentsPathURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

        return ["database.db", "database_cipher3.db", "database_cipher4.db"].map {
            documentsPathURL.appendingPathComponent($0).absoluteString
        }
    }
}

Intercept network requests

let uid = UUID().uuidString

let request = URLRequest(url: url)

// send request to the frontend
IOSInspector.sendRequest(withUID: uid, request: request)

URLSession.shared.dataTask(with: request) { data, response, error in

    if let data = data, let response = response as? HTTPURLResponse {
        // send response to the frontend
        IOSInspector.sendResponse(withUID: uid, response: response, body: data)
    }

}.resume()

Static plugins

Accepts returning JSON, HTML or plain text

IOSInspector.addPlugin("prefs", name: "User Defaults") {
    let dict = UserDefaults.standard.dictionaryRepresentation()
    if let data = try? JSONSerialization.data(withJSONObject: dict),
        let json = String(data: data, encoding: .utf8) {
        return json
    }
    return "No data"
}

Live plugins

Accepts complex HTML frontend with javascript support
Check ExplorerPlugin.swift for a full example

IOSInspector.addLivePlugin("explorer", name: "Explorer") {
    // return plugin frontend
}

Plugin API

Route with parameters to be used as a plugin or standalone api
Check ExplorerPlugin.swift for a full example

IOSInspector.addPluginAPI(forMethod: "GET", path: "filesystem/list") { params -> String in
    // return json array with list of files
}

IOSInspector.addPluginAPI(forMethod: "GET", path: "filesystem/open") { params -> Data? in
    // return file contents
}

Websockets

Send messages to your live plugins

new WebSocket(`ws://${location.hostname}:${location.port}/plugins/ws/mykey`)
IOSInspector.sendMessage(to: "mykey", message: "Hello world!")