Capture your Mobile Application's Network Logs from Automation - Part 2
Let's intercept network logs from automation framework
In Part-1 of this tutorial, we learned how to intercept HTTPS Requests using MITM Proxy.
In Part-2 will use a proxy Java Client (https://github.com/appium/mitmproxy-java) to intercept and capture requests from our automation framework.
What is mitmproxy java client?
mitmproxy-java
starts a WebSocket server and a Python plugin for mitmproxy
connects to it and sends requests over. The two communicate via binary messages.
Pre-Requisites
mitmproxy
v9
must be installed and runnable from the terminal. If the installation method is a prebuilt binary or homebrew, install websockets manually since those packages are missing the Python websockets module. Install viapip
or from the source.Python 3.6 and above, since we use the new async/await syntax in the mitmproxy plugin
pip3 install websockets
Maven:
<dependency>
<groupId>io.appium</groupId>
<artifactId>mitmproxy-java</artifactId>
<version>2.0.2</version>
</dependency>
The latest version of code is still not available in mitm artifactory, please clone and build your own local jar to use this.
Once installed add MITMProxy until in our framework
Create class to add timestamp in captured data
import io.appium.mitmproxy.InterceptedMessage;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* Stores intercepted message along with timestamp
*/
public class InterceptedMessages{
@Accessors(chain = true)
@Getter@Setter
private Date timestamp;
@Accessors(chain = true)
@Getter@Setter
private InterceptedMessage interceptedMessage;
}
Add handler to start/stop proxy
import com.project.automation.InterceptedMessages;
import io.appium.mitmproxy.InterceptedMessage;
import io.appium.mitmproxy.MitmproxyJava;
import lombok.Getter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeoutException;
/**
* Man In The Middle Proxy Utility
*/
public class MITMProxy {
@Getter
private final List<InterceptedMessages> networkCalls = new ArrayList<>();
private static MITMProxy proxyInstance = null;
MitmproxyJava proxy;
private MITMProxy(){
startProxyListener();
}
public static MITMProxy getProxy()
{
if (proxyInstance == null)
proxyInstance = new MITMProxy();
return proxyInstance;
}
private void startProxyListener() {
System.out.println("Starting Proxy Listener");
List<String> extraMitmproxyParams = Arrays.asList(
"--showhost",
"<domain-name-filter>");
int mitmproxyPort = 8090;
this.proxy = new MitmproxyJava(
getMitmDumpPath(), (InterceptedMessage m) -> {
InterceptedMessages message = new InterceptedMessages()
.setTimestamp(new Date())
.setInterceptedMessage(m);
networkCalls.add(message);
return m;
}, mitmproxyPort, extraMitmproxyParams);
try {
String processId = ProcessExecutor
.executeCommandSync("lsof -t -i:" + mitmproxyPort + " -sTCP:LISTEN")
.replaceAll("\\s", "");
if(!processId.isEmpty())
ProcessExecutor.executeCommandSync("kill -9 " + processId);
this.proxy.start();
} catch (IOException | TimeoutException e) {
throw new RuntimeException(e);
}
System.out.println("Proxy Listener Started");
}
private String getMitmDumpPath() {
String result = ProcessExecutor
.executeCommandSync("whereis mitmdump");
result = result.split("mitmdump: ")[1];
result = result.substring(0, result.indexOf('\n'));
result = result.split(" ")[0];
System.out.println("mitmdump path is: " + result);
return result;
}
public void stopProxyListener() {
System.out.println("Stopping Proxy Listener");
try {
this.proxy.stop();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("Proxy Listener Stopped");
}
}
Start Proxy Using
MITMProxy.getProxy();
Fetch intercepted data using
networkLogMessage = MITMProxy.getProxy().getnetworkCalls()
Stop Proxy Using
MITMProxy.getProxy().stopProxyListener();