Verified Commit 87367fcc authored by Sarath's avatar Sarath
Browse files

new tor service

parent aaa421af
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
buildToolsVersion '28.0.3'
compileSdkVersion 30
buildToolsVersion "29.0.3"
flavorDimensions "versionCode"
defaultConfig {
applicationId "com.samourai.sentinel"
minSdkVersion 21
targetSdkVersion 28
targetSdkVersion 30
versionCode 49
versionName '3.6'
multiDexEnabled true
......@@ -44,7 +44,7 @@ android {
production {
minSdkVersion 21
applicationId 'com.samourai.sentinel'
targetSdkVersion 28
targetSdkVersion 30
versionCode 49
versionName '3.6'
resValue "string", "app_name", "Sentinel"
......@@ -68,9 +68,9 @@ android {
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:multidex:1.0.3'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.baoyz.swipemenulistview:library:1.2.1'
implementation 'com.neovisionaries:nv-websocket-client:1.9'
implementation 'commons-codec:commons-codec:1.4'
......@@ -81,19 +81,21 @@ dependencies {
implementation 'com.lambdaworks:scrypt:1.4.0'
implementation 'net.i2p.android.ext:floatingactionbutton:1.9.0'
implementation 'com.squareup.picasso:picasso:2.5.2'
implementation 'com.android.support:design:28.0.0'
implementation 'com.google.android.material:material:1.2.0'
implementation('com.google.zxing:core:3.3.0') {
transitive = true
}
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.yanzhenjie.zbar:camera:1.0.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'com.auth0.android:jwtdecode:1.1.1'
implementation 'com.squareup.okhttp3:okhttp:3.13.1'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'
implementation project(path: ':tor')
implementation project(path: ':torservice')
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
}
......
......@@ -22,6 +22,7 @@
android:allowBackup="false"
android:usesCleartextTraffic="true"
android:name=".SentinelApplication"
tools:replace="android:allowBackup"
tools:ignore="GoogleAppIndexingWarning">
<service
android:name=".tor.TorService"
......
......@@ -11,5 +11,6 @@ public class TorBroadCastReceiver extends BroadcastReceiver {
Intent serviceIntent = new Intent(context, TorService.class);
serviceIntent.setAction(intent.getAction());
context.startService(serviceIntent);
}
}
package com.samourai.sentinel.tor;
import android.content.Context;
import android.util.Log;
import com.invertedx.torservice.TorProxyManager;
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 java.util.Map;
import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.subjects.PublishSubject;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject;
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;
public static TorManager getInstance(Context context) {
if (instance == null) {
instance = new TorManager(context);
}
return instance;
}
private TorManager(Context context) {
torStatus.onNext(CONNECTION_STATES.DISCONNECTED);
onionProxyManager = new AndroidOnionProxyManager(context, fileStorageLocation);
}
Context context;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
TorProxyManager torProxyManager;
TorProxyManager.ConnectionStatus status = TorProxyManager.ConnectionStatus.IDLE;
public Observable<Proxy> startTor() {
Log.i(TAG, "startTor: ");
private TorManager(Context context) {
this.context = context;
torProxyManager = new TorProxyManager(context);
Disposable disposable = torProxyManager.torStatus
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(status ->{
this.status = status;
});
compositeDisposable.add(disposable);
}
Observable<Boolean> 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;
}
torProxyManager.startTor();
return true;
});
}
public String getLatestLogs() {
public boolean isConnected() {
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 "";
return status == TorProxyManager.ConnectionStatus.CONNECTED;
} catch (Exception Ex) {
return false;
}
}
private void setProxy(int port) {
this.proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", port));
public TorProxyManager.ConnectionStatus getStatus() {
return status;
}
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 Completable stopTor() {
return torProxyManager.stopTor();
}
public boolean isConnected() {
Log.i(TAG, "isConnected: ");
return this.state == CONNECTION_STATES.CONNECTED;
public Completable renew() {
return torProxyManager.newIdentity();
}
public Proxy getProxy() {
return proxy;
public BehaviorSubject<TorProxyManager.ConnectionStatus> getTorStatus() {
return torProxyManager.torStatus;
}
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;
}
public boolean isRequired() {
return PrefsUtil.getInstance(context).getValue(PrefsUtil.ENABLE_TOR, false);
}
return true;
});
public Subject<String> getTorLogs() {
return torProxyManager.torLogs;
}
public Subject<String> getCircuitLogs() {
return torProxyManager.torCircuitStatus;
}
public Subject<CONNECTION_STATES> getTorStatus() {
return torStatus;
public Subject<Map<String, Long>> getBandWidth() {
return torProxyManager.bandWidthStatus;
}
public Proxy getProxy() {
return torProxyManager.getProxy();
}
public void setTorState(CONNECTION_STATES state) {
this.state = state;
if (torStatus.hasObservers()) {
torStatus.onNext(state);
}
public void dispose() {
compositeDisposable.dispose();
}
public static boolean isPortOpen(final String ip, final int port, final int timeout) {
public void fromJSON(JSONObject jsonPayload) {
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;
if (jsonPayload.has("active")) {
PrefsUtil.getInstance(context).setValue(PrefsUtil.ENABLE_TOR, jsonPayload.getBoolean("active"));
}
} catch (JSONException ex) {
throw new RuntimeException(ex);
}
}
public JSONObject toJSON() {
......@@ -216,28 +125,11 @@ public class TorManager {
jsonPayload.put("active", PrefsUtil.getInstance(context).getValue(PrefsUtil.ENABLE_TOR, false));
}
catch(JSONException je) {
} 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);
}
}
}
......@@ -2,7 +2,7 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
compileSdkVersion 30
buildToolsVersion "29.0.3"
sourceSets {
......@@ -16,7 +16,7 @@ android {
}
defaultConfig {
minSdkVersion 21
targetSdkVersion 29
targetSdkVersion 30
versionCode 1
versionName "1.0"
......@@ -29,6 +29,8 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
applicationVariants {
}
}
aaptOptions {
......@@ -48,8 +50,8 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.core:core-ktx:1.3.1'
testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment