Skip to content

Commit

Permalink
Tor package for Tor service and TorManager
Browse files Browse the repository at this point in the history
  • Loading branch information
InvertedX committed Sep 16, 2019
1 parent 649dcc1 commit a0ebd91
Show file tree
Hide file tree
Showing 3 changed files with 572 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.samourai.sentinel.tor;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class TorBroadCastReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context, TorService.class);
serviceIntent.setAction(intent.getAction());
context.startService(serviceIntent);
}
}
243 changes: 243 additions & 0 deletions app/src/main/java/com/samourai/sentinel/tor/TorManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
package com.samourai.sentinel.tor;

import android.content.Context;
import android.util.Log;

import com.samourai.sentinel.util.PrefsUtil;
import com.msopentech.thali.android.toronionproxy.AndroidOnionProxyManager;
import com.msopentech.thali.toronionproxy.OnionProxyManager;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;

import io.reactivex.Observable;
import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject;

public class TorManager {
private static final String TAG = "TorManager";
private boolean changingIdentity = false;

public boolean newIDentity() {
return this.onionProxyManager.newIdentity();
}

public enum CONNECTION_STATES {
IDLE,
CONNECTED,
DISCONNECTED,
CONNECTING
}

static TorManager instance;
private int currentPort = 0;

private Proxy proxy = null;
public CONNECTION_STATES state = CONNECTION_STATES.IDLE;
public Subject<CONNECTION_STATES> torStatus = PublishSubject.create();
private OnionProxyManager onionProxyManager;
public boolean isProcessRunning = false;
String fileStorageLocation = "torfiles";

private static Context context = null;

public static TorManager getInstance(Context ctx) {

context = ctx;

if (instance == null) {
instance = new TorManager(context);
}
return instance;
}

private TorManager(Context context) {

torStatus.onNext(CONNECTION_STATES.DISCONNECTED);
onionProxyManager = new AndroidOnionProxyManager(context, fileStorageLocation);
}

public Observable<Proxy> startTor() {
Log.i(TAG, "startTor: ");
return Observable.fromCallable(() -> {
state = CONNECTION_STATES.CONNECTING;
torStatus.onNext(CONNECTION_STATES.CONNECTING);

int totalSecondsPerTorStartup = 4 * 60;
int totalTriesPerTorStartup = 5;
try {
boolean ok = onionProxyManager.startWithRepeat(totalSecondsPerTorStartup, totalTriesPerTorStartup);
if (!ok) {
System.out.println("Couldn't start tor");
throw new RuntimeException("Couldn't start tor");
}
while (!onionProxyManager.isRunning())
Thread.sleep(90);
proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", onionProxyManager.getIPv4LocalHostSocksPort()));
currentPort = onionProxyManager.getIPv4LocalHostSocksPort();
if (torStatus.hasObservers()) {
torStatus.onNext(CONNECTION_STATES.CONNECTED);
}
isProcessRunning = true;
state = CONNECTION_STATES.CONNECTED;

return proxy;
} catch (Exception e) {
e.printStackTrace();

if (!onionProxyManager.isRunning()) {
state = CONNECTION_STATES.DISCONNECTED;
if (torStatus.hasObservers()) {
torStatus.onNext(CONNECTION_STATES.DISCONNECTED);
}
}
e.printStackTrace();
return proxy;
}
});

}

public String getLatestLogs() {
try {
if (onionProxyManager != null && onionProxyManager.isRunning()) {
String log = onionProxyManager.getLastLog();
try {
if (!TorManager.isPortOpen("127.0.0.1", onionProxyManager.getIPv4LocalHostSocksPort(), 4000)) {
this.state = CONNECTION_STATES.DISCONNECTED;
if (torStatus.hasObservers()) {
torStatus.onNext(CONNECTION_STATES.DISCONNECTED);
}
}
int port = onionProxyManager.getIPv4LocalHostSocksPort();
if (currentPort != port) {
setProxy(port);
}

} catch (Exception e) {
Log.i(TAG, "getLatestLogs: LOG");
e.printStackTrace();
}
return log;
} else {
return "Disconnected state";
}
} catch (IOException e) {
e.printStackTrace();
return "";
}
}

private void setProxy(int port) {
this.proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", port));
}

public boolean isRequired() {
Log.i(TAG, "isRequired: ".concat(String.valueOf(PrefsUtil.getInstance(context).getValue(PrefsUtil.ENABLE_TOR, false))));
return PrefsUtil.getInstance(context).getValue(PrefsUtil.ENABLE_TOR, false);
}

public boolean isConnected() {
Log.i(TAG, "isConnected: ");
return this.state == CONNECTION_STATES.CONNECTED;
}

public Proxy getProxy() {
return proxy;
}

public Observable<Boolean> stopTor() {
Log.i(TAG, "stopTor: ");
if (torStatus.hasObservers()) {
torStatus.onNext(CONNECTION_STATES.DISCONNECTED);
state = CONNECTION_STATES.DISCONNECTED;
}
return Observable.fromCallable(() -> {
try {
this.state = CONNECTION_STATES.DISCONNECTED;
if (torStatus.hasObservers()) {
torStatus.onNext(CONNECTION_STATES.DISCONNECTED);
}
isProcessRunning = false;
} catch (Exception ex) {
ex.printStackTrace();
this.state = CONNECTION_STATES.DISCONNECTED;
if (torStatus.hasObservers()) {
torStatus.onNext(CONNECTION_STATES.DISCONNECTED);
}
isProcessRunning = false;
return false;
}

return true;
});

}

public Subject<CONNECTION_STATES> getTorStatus() {
return torStatus;
}


public void setTorState(CONNECTION_STATES state) {
this.state = state;
if (torStatus.hasObservers()) {
torStatus.onNext(state);
}
}

public static boolean isPortOpen(final String ip, final int port, final int timeout) {

try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return true;
} catch (ConnectException ce) {
ce.printStackTrace();
return false;
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
}

public JSONObject toJSON() {

JSONObject jsonPayload = new JSONObject();

try {

jsonPayload.put("active", PrefsUtil.getInstance(context).getValue(PrefsUtil.ENABLE_TOR, false));

}
catch(JSONException je) {
;
}

return jsonPayload;
}

public void fromJSON(JSONObject jsonPayload) {

try {

if(jsonPayload.has("active")) {
PrefsUtil.getInstance(context).setValue(PrefsUtil.ENABLE_TOR, jsonPayload.getBoolean("active"));
}

}
catch(JSONException ex) {
throw new RuntimeException(ex);
}

}


}
Loading

0 comments on commit a0ebd91

Please sign in to comment.