From fe6a0e47121d17d08c7d913f1db086687a569446 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 23 Jun 2021 03:27:17 +0200 Subject: initial tor-integration to circumvent blocking attempts of the provider api --- .../se/leap/bitmaskclient/base/BitmaskApp.java | 4 + .../leap/bitmaskclient/base/models/Constants.java | 1 + .../bitmaskclient/base/utils/PreferenceHelper.java | 14 ++- .../leap/bitmaskclient/eip/EipSetupObserver.java | 37 +++++- .../bitmaskclient/providersetup/ProviderAPI.java | 134 +++++++++++++++++++++ .../providersetup/ProviderAPICommand.java | 18 +-- .../providersetup/ProviderApiManagerBase.java | 72 +++++++++-- .../connectivity/OkHttpClientGenerator.java | 25 ++-- .../bitmaskclient/tor/TorNotificationManager.java | 105 ++++++++++++++++ .../bitmaskclient/tor/TorStatusObservable.java | 102 ++++++++++++++++ 10 files changed, 478 insertions(+), 34 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java index 4b6fea72..60c28a9a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java @@ -34,6 +34,8 @@ import se.leap.bitmaskclient.eip.EipSetupObserver; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.tethering.TetheringStateManager; import se.leap.bitmaskclient.base.utils.PRNGFixes; +import se.leap.bitmaskclient.tor.TorNotificationManager; +import se.leap.bitmaskclient.tor.TorStatusObservable; import static android.content.Intent.CATEGORY_DEFAULT; import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_DOWNLOAD_SERVICE_EVENT; @@ -53,6 +55,7 @@ public class BitmaskApp extends MultiDexApplication { private RefWatcher refWatcher; private ProviderObservable providerObservable; private DownloadBroadcastReceiver downloadBroadcastReceiver; + private TorStatusObservable torStatusObservable; @Override @@ -69,6 +72,7 @@ public class BitmaskApp extends MultiDexApplication { SharedPreferences preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); providerObservable = ProviderObservable.getInstance(); providerObservable.updateProvider(getSavedProviderFromSharedPreferences(preferences)); + torStatusObservable = TorStatusObservable.getInstance(); EipSetupObserver.init(this, preferences); AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); TetheringStateManager.getInstance().init(this); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java index 3edfbb3d..f627a24e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java @@ -41,6 +41,7 @@ public interface Constants { String RESTART_ON_UPDATE = "restart_on_update"; String LAST_UPDATE_CHECK = "last_update_check"; String PREFERRED_CITY = "preferred_city"; + String USE_TOR = "use_tor"; ////////////////////////////////////////////// diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java index a3d1314e..cbea2815 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java @@ -34,6 +34,7 @@ import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.base.models.Constants.SHOW_EXPERIMENTAL; import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL; import static se.leap.bitmaskclient.base.models.Constants.USE_PLUGGABLE_TRANSPORTS; +import static se.leap.bitmaskclient.base.models.Constants.USE_TOR; /** * Created by cyberta on 18.03.18. @@ -212,6 +213,18 @@ public class PreferenceHelper { putString(context, PREFERRED_CITY, city); } + public static Boolean useTor(SharedPreferences preferences) { + return preferences.getBoolean(USE_TOR, true); + } + + public static boolean useTor(Context context) { + return getBoolean(context, USE_TOR, true); + } + + public static void setUseTor(Context context, boolean useTor) { + putBoolean(context, USE_TOR, useTor); + } + public static JSONObject getEipDefinitionFromPreferences(SharedPreferences preferences) { JSONObject result = new JSONObject(); try { @@ -278,5 +291,4 @@ public class PreferenceHelper { SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); preferences.edit().putBoolean(key, value).apply(); } - } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java index 1ad5f7d2..45c829b6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java @@ -28,27 +28,29 @@ import android.util.Log; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.json.JSONObject; +import org.torproject.jni.TorService; import java.util.Vector; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import de.blinkt.openvpn.LaunchVPN; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.LogItem; import de.blinkt.openvpn.core.VpnStatus; +import se.leap.bitmaskclient.appUpdate.DownloadServiceCommand; import se.leap.bitmaskclient.base.models.Provider; -import se.leap.bitmaskclient.providersetup.ProviderAPI; -import se.leap.bitmaskclient.providersetup.ProviderAPICommand; import se.leap.bitmaskclient.base.models.ProviderObservable; -import se.leap.bitmaskclient.appUpdate.DownloadServiceCommand; import se.leap.bitmaskclient.base.utils.PreferenceHelper; +import se.leap.bitmaskclient.providersetup.ProviderAPI; +import se.leap.bitmaskclient.providersetup.ProviderAPICommand; +import se.leap.bitmaskclient.tor.TorStatusObservable; import static android.app.Activity.RESULT_CANCELED; import static android.content.Intent.CATEGORY_DEFAULT; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NOTCONNECTED; +import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.CHECK_VERSION_FILE; import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_EIP_EVENT; import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT; import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_PROVIDER_API_EVENT; @@ -67,7 +69,8 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOAD import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON; -import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.CHECK_VERSION_FILE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.STOP_PROXY; +import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; /** * Created by cyberta on 05.12.18. @@ -92,6 +95,8 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT); updateIntentFilter.addAction(BROADCAST_EIP_EVENT); updateIntentFilter.addAction(BROADCAST_PROVIDER_API_EVENT); + updateIntentFilter.addAction(TorService.ACTION_STATUS); + updateIntentFilter.addAction(TorService.ACTION_ERROR); updateIntentFilter.addCategory(CATEGORY_DEFAULT); LocalBroadcastManager.getInstance(context.getApplicationContext()).registerReceiver(this, updateIntentFilter); instance = this; @@ -140,11 +145,30 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta case BROADCAST_PROVIDER_API_EVENT: handleProviderApiEvent(intent); break; + case TorService.ACTION_STATUS: + handleTorStatusEvent(intent); + break; + case TorService.ACTION_ERROR: + handleTorErrorEvent(intent); + break; default: break; } } + private void handleTorErrorEvent(Intent intent) { + String error = intent.getStringExtra(Intent.EXTRA_TEXT); + Log.d(TAG, "handle Tor error event: " + error); + TorStatusObservable.setLastError(error); + } + + private void handleTorStatusEvent(Intent intent) { + String status = intent.getStringExtra(TorService.EXTRA_STATUS); + Log.d(TAG, "handle Tor status event: " + status); + TorStatusObservable.updateState(context, status); + } + + private void handleProviderApiEvent(Intent intent) { int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, RESULT_CANCELED); Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY); @@ -324,6 +348,9 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta setupNClosestGateway.set(0); observedProfileFromVpnStatus = null; this.changingGateway.set(changingGateway); + if (TorStatusObservable.getStatus() != OFF) { + ProviderAPICommand.execute(context.getApplicationContext(), STOP_PROXY, null); + } } /** diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index 23c750a3..dcbe9636 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -17,17 +17,36 @@ package se.leap.bitmaskclient.providersetup; import android.annotation.SuppressLint; +import android.app.Notification; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.content.SharedPreferences; +import android.os.Build; +import android.os.IBinder; +import android.util.Log; import androidx.annotation.NonNull; import androidx.core.app.JobIntentService; import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import org.torproject.jni.TorService; + +import java.io.Closeable; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator; +import se.leap.bitmaskclient.tor.TorNotificationManager; +import se.leap.bitmaskclient.tor.TorStatusObservable; import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread; +import static se.leap.bitmaskclient.tor.TorNotificationManager.TOR_SERVICE_NOTIFICATION_ID; +import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; +import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.STOPPING; /** * Implements HTTP api methods (encapsulated in {{@link ProviderApiManager}}) @@ -49,6 +68,7 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB final public static String TAG = ProviderAPI.class.getSimpleName(), + STOP_PROXY = "stopProxy", SET_UP_PROVIDER = "setUpProvider", UPDATE_PROVIDER_DETAILS = "updateProviderDetails", DOWNLOAD_GEOIP_JSON = "downloadGeoIpJson", @@ -85,6 +105,7 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB INCORRECTLY_DOWNLOADED_GEOIP_JSON = 18; ProviderApiManager providerApiManager; + private volatile TorServiceConnection torServiceConnection; //TODO: refactor me, please! //used in insecure flavor only @@ -115,14 +136,127 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB providerApiManager.handleIntent(command); } + @Override + public void onDestroy() { + super.onDestroy(); + if (torServiceConnection != null) { + torServiceConnection.close(); + torServiceConnection = null; + } + } + @Override public void broadcastEvent(Intent intent) { LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } + + + @Override + public int initTorConnection() { + initTorServiceConnection(this); + if (torServiceConnection != null) { + Intent torServiceIntent = new Intent(this, TorService.class); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Notification notification = TorNotificationManager.buildTorForegroundNotification(getApplicationContext()); + //noinspection NewApi + getApplicationContext().startForegroundService(torServiceIntent); + torServiceConnection.torService.startForeground(TOR_SERVICE_NOTIFICATION_ID, notification); + } else { + getApplicationContext().startService(torServiceIntent); + } + + return torServiceConnection.torService.getHttpTunnelPort(); + } + + return -1; + } + + @Override + public void stopTorConnection() { + if (TorStatusObservable.getStatus() != OFF) { + TorStatusObservable.updateState(this, STOPPING.toString()); + initTorServiceConnection(this); + if (torServiceConnection != null) { + torServiceConnection.torService.stopSelf(); + } + } + } + private ProviderApiManager initApiManager() { SharedPreferences preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); OkHttpClientGenerator clientGenerator = new OkHttpClientGenerator(getResources()); return new ProviderApiManager(preferences, getResources(), clientGenerator, this); } + + /** + * Assigns a new TorServiceConnection to ProviderAPI's member variable torServiceConnection. + * Only one thread at a time can create the service connection, that will be shared between threads + * + * @throws InterruptedException thrown if thread gets interrupted + * @throws IllegalStateException thrown if this method was not called from a background thread + */ + private void initTorServiceConnection(Context context) { + if (PreferenceHelper.useTor(context)) { + try { + if (torServiceConnection == null) { + Log.d(TAG, "serviceConnection is still null"); + torServiceConnection = new TorServiceConnection(context); + } + } catch (InterruptedException | IllegalStateException e) { + e.printStackTrace(); + } + } + } + + public static class TorServiceConnection implements Closeable { + private final Context context; + private ServiceConnection serviceConnection; + private TorService torService; + + TorServiceConnection(Context context) throws InterruptedException, IllegalStateException { + this.context = context; + ensureNotOnMainThread(context); + Log.d(TAG, "initSynchronizedServiceConnection!"); + initSynchronizedServiceConnection(context); + } + + @Override + public void close() { + context.unbindService(serviceConnection); + } + + private void initSynchronizedServiceConnection(final Context context) throws InterruptedException { + final BlockingQueue blockingQueue = new LinkedBlockingQueue<>(1); + this.serviceConnection = new ServiceConnection() { + volatile boolean mConnectedAtLeastOnce = false; + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (!mConnectedAtLeastOnce) { + mConnectedAtLeastOnce = true; + try { + TorService.LocalBinder binder = (TorService.LocalBinder) service; + blockingQueue.put(binder.getService()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + } + }; + Intent intent = new Intent(context, TorService.class); + context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); + torService = blockingQueue.take(); + } + + public TorService getService() { + return torService; + } + } + } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPICommand.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPICommand.java index 1408dce8..3cdfcab0 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPICommand.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPICommand.java @@ -13,12 +13,12 @@ import se.leap.bitmaskclient.base.models.Provider; public class ProviderAPICommand { private static final String TAG = ProviderAPICommand.class.getSimpleName(); - private Context context; + private final Context context; - private String action; - private Bundle parameters; - private ResultReceiver resultReceiver; - private Provider provider; + private final String action; + private final Bundle parameters; + private final ResultReceiver resultReceiver; + private final Provider provider; private ProviderAPICommand(@NonNull Context context, @NonNull String action, @NonNull Provider provider, ResultReceiver resultReceiver) { this(context.getApplicationContext(), action, Bundle.EMPTY, provider, resultReceiver); @@ -64,22 +64,22 @@ public class ProviderAPICommand { return command; } - public static void execute(Context context, String action, @NonNull Provider provider) { + public static void execute(Context context, String action, Provider provider) { ProviderAPICommand command = new ProviderAPICommand(context, action, provider); command.execute(); } - public static void execute(Context context, String action, Bundle parameters, @NonNull Provider provider) { + public static void execute(Context context, String action, Bundle parameters, Provider provider) { ProviderAPICommand command = new ProviderAPICommand(context, action, parameters, provider); command.execute(); } - public static void execute(Context context, String action, Bundle parameters, @NonNull Provider provider, ResultReceiver resultReceiver) { + public static void execute(Context context, String action, Bundle parameters, Provider provider, ResultReceiver resultReceiver) { ProviderAPICommand command = new ProviderAPICommand(context, action, parameters, provider, resultReceiver); command.execute(); } - public static void execute(Context context, String action, @NonNull Provider provider, ResultReceiver resultReceiver) { + public static void execute(Context context, String action, Provider provider, ResultReceiver resultReceiver) { ProviderAPICommand command = new ProviderAPICommand(context, action, provider, resultReceiver); command.execute(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index c5dc6572..8118c872 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -48,6 +48,9 @@ import java.security.interfaces.RSAPrivateKey; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; +import java.util.Observer; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLPeerUnverifiedException; @@ -59,10 +62,13 @@ import se.leap.bitmaskclient.base.models.Constants.CREDENTIAL_ERRORS; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.utils.ConfigHelper; +import se.leap.bitmaskclient.base.utils.PreferenceHelper; +import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator; import se.leap.bitmaskclient.providersetup.models.LeapSRPSession; import se.leap.bitmaskclient.providersetup.models.SrpCredentials; import se.leap.bitmaskclient.providersetup.models.SrpRegistrationData; +import se.leap.bitmaskclient.tor.TorStatusObservable; import static se.leap.bitmaskclient.R.string.certificate_error; import static se.leap.bitmaskclient.R.string.error_io_exception_user_message; @@ -119,6 +125,7 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_OK; import static se.leap.bitmaskclient.providersetup.ProviderAPI.RECEIVER_KEY; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SET_UP_PROVIDER; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SIGN_UP; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.STOP_PROXY; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_LOGIN; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_LOGOUT; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_SIGNUP; @@ -128,6 +135,8 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE; import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING; import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON; import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_INVALID_CERTIFICATE; +import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.ON; +import static se.leap.bitmaskclient.tor.TorStatusObservable.getProxyPort; /** * Implements the logic of the http api calls. The methods of this class needs to be called from @@ -140,9 +149,11 @@ public abstract class ProviderApiManagerBase { public interface ProviderApiServiceCallback { void broadcastEvent(Intent intent); + int initTorConnection(); + void stopTorConnection(); } - private ProviderApiServiceCallback serviceCallback; + private final ProviderApiServiceCallback serviceCallback; protected SharedPreferences preferences; protected Resources resources; @@ -164,17 +175,22 @@ public abstract class ProviderApiManagerBase { String action = command.getAction(); Bundle parameters = command.getBundleExtra(PARAMETERS); - Provider provider = command.getParcelableExtra(PROVIDER_KEY); + if (action == null) { + Log.e(TAG, "Intent without action sent!"); + return; + } - if (provider == null) { + Provider provider = null; + if (command.getParcelableExtra(PROVIDER_KEY) != null) { + provider = command.getParcelableExtra(PROVIDER_KEY); + } else if (!STOP_PROXY.equals(action)) { //TODO: consider returning error back e.g. NO_PROVIDER Log.e(TAG, action +" called without provider!"); return; } - if (action == null) { - Log.e(TAG, "Intent without action sent!"); - return; - } + + // uncomment for testing --v + TorStatusObservable.setProxyPort(startTorProxy()); Bundle result = new Bundle(); switch (action) { @@ -269,9 +285,43 @@ public abstract class ProviderApiManagerBase { } ProviderObservable.getInstance().setProviderForDns(null); } + break; + case STOP_PROXY: + serviceCallback.stopTorConnection(); + break; } } + protected int startTorProxy() { + int port = -1; + if (PreferenceHelper.useTor(preferences) && EipStatus.getInstance().isDisconnected() ) { + port = serviceCallback.initTorConnection(); + if (port != -1) { + try { + waitForTorCircuits(); + } catch (InterruptedException e) { + e.printStackTrace(); + port = -1; + } + } + } + return port; + } + + private void waitForTorCircuits() throws InterruptedException { + if (TorStatusObservable.getStatus() == ON) { + return; + } + CountDownLatch countDownLatch = new CountDownLatch(1); + Observer observer = (o, arg) -> { + if (TorStatusObservable.getStatus() == ON) { + countDownLatch.countDown(); + } + }; + TorStatusObservable.getInstance().addObserver(observer); + countDownLatch.await(90, TimeUnit.SECONDS); + } + void resetProviderDetails(Provider provider) { provider.reset(); deleteProviderDetailsFromPreferences(preferences, provider.getDomain()); @@ -342,7 +392,7 @@ public abstract class ProviderApiManagerBase { private Bundle register(Provider provider, String username, String password) { JSONObject stepResult = null; - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), stepResult); + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), getProxyPort(), stepResult); if (okHttpClient == null) { return backendErrorNotification(stepResult, username); } @@ -401,7 +451,7 @@ public abstract class ProviderApiManagerBase { String providerApiUrl = provider.getApiUrlWithVersion(); - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), stepResult); + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), getProxyPort(), stepResult); if (okHttpClient == null) { return backendErrorNotification(stepResult, username); } @@ -681,7 +731,7 @@ public abstract class ProviderApiManagerBase { JSONObject errorJson = new JSONObject(); String providerUrl = provider.getApiUrlString() + "/provider.json"; - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), errorJson); + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), getProxyPort(), errorJson); if (okHttpClient == null) { result.putString(ERRORS, errorJson.toString()); return false; @@ -950,7 +1000,7 @@ public abstract class ProviderApiManagerBase { } private boolean logOut(Provider provider) { - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), new JSONObject()); + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), getProxyPort(), new JSONObject()); if (okHttpClient == null) { return false; } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/OkHttpClientGenerator.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/OkHttpClientGenerator.java index 2077a8b9..ea619263 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/OkHttpClientGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/OkHttpClientGenerator.java @@ -18,6 +18,7 @@ package se.leap.bitmaskclient.providersetup.connectivity; import android.content.res.Resources; +import android.net.LocalSocketAddress; import android.os.Build; import androidx.annotation.NonNull; @@ -26,6 +27,9 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.SocketAddress; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStoreException; @@ -50,6 +54,7 @@ import static se.leap.bitmaskclient.R.string.certificate_error; import static se.leap.bitmaskclient.R.string.error_io_exception_user_message; import static se.leap.bitmaskclient.R.string.error_no_such_algorithm_exception_user_message; import static se.leap.bitmaskclient.R.string.keyChainAccessError; +import static se.leap.bitmaskclient.R.string.proxy; import static se.leap.bitmaskclient.R.string.server_unreachable_message; import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString; @@ -61,34 +66,35 @@ import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormatted public class OkHttpClientGenerator { Resources resources; + private final static String PROXY_HOST = "127.0.0.1"; public OkHttpClientGenerator(/*SharedPreferences preferences,*/ Resources resources) { this.resources = resources; } - public OkHttpClient initCommercialCAHttpClient(JSONObject initError) { - return initHttpClient(initError, null); + public OkHttpClient initCommercialCAHttpClient(JSONObject initError, int proxyPort) { + return initHttpClient(initError, null, proxyPort); } - public OkHttpClient initSelfSignedCAHttpClient(String caCert, JSONObject initError) { - return initHttpClient(initError, caCert); + public OkHttpClient initSelfSignedCAHttpClient(String caCert, int proxyPort, JSONObject initError) { + return initHttpClient(initError, caCert, proxyPort); } public OkHttpClient init() { try { - return createClient(null); + return createClient(null, -1); } catch (Exception e) { e.printStackTrace(); } return null; } - private OkHttpClient initHttpClient(JSONObject initError, String certificate) { + private OkHttpClient initHttpClient(JSONObject initError, String certificate, int proxyPort) { if (resources == null) { return null; } try { - return createClient(certificate); + return createClient(certificate, proxyPort); } catch (IllegalArgumentException e) { e.printStackTrace(); // TODO ca cert is invalid - show better error ?! @@ -117,7 +123,7 @@ public class OkHttpClientGenerator { return null; } - private OkHttpClient createClient(String certificate) throws Exception { + private OkHttpClient createClient(String certificate, int proxyPort) throws Exception { TLSCompatSocketFactory sslCompatFactory; ConnectionSpec spec = getConnectionSpec(); OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); @@ -131,6 +137,9 @@ public class OkHttpClientGenerator { clientBuilder.cookieJar(getCookieJar()) .connectionSpecs(Collections.singletonList(spec)); clientBuilder.dns(new DnsResolver()); + if (proxyPort != -1) { + clientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_HOST, proxyPort))); + } return clientBuilder.build(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java new file mode 100644 index 00000000..71a2735c --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java @@ -0,0 +1,105 @@ +package se.leap.bitmaskclient.tor; +/** + * Copyright (c) 2021 LEAP Encryption Access Project and contributers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import android.annotation.TargetApi; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.os.Build; + +import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; + +import se.leap.bitmaskclient.R; + +public class TorNotificationManager { + public final static int TOR_SERVICE_NOTIFICATION_ID = 10; + static final String NOTIFICATION_CHANNEL_NEWSTATUS_ID = "bitmask_tor_service_news"; + + + public TorNotificationManager() {} + + + public static Notification buildTorForegroundNotification(Context context) { + NotificationManager notificationManager = initNotificationManager(context); + if (notificationManager == null) { + return null; + } + NotificationCompat.Builder notificationBuilder = initNotificationBuilderDefaults(context); + return notificationBuilder + .setSmallIcon(R.drawable.ic_bridge_36) + .setWhen(System.currentTimeMillis()) + .setContentTitle("Using Bridges to configure provider.").build(); + } + + public void buildTorNotification(Context context, String state) { + NotificationManager notificationManager = initNotificationManager(context); + if (notificationManager == null) { + return; + } + NotificationCompat.Builder notificationBuilder = initNotificationBuilderDefaults(context); + notificationBuilder + .setSmallIcon(R.drawable.ic_bridge_36) + .setWhen(System.currentTimeMillis()) + .setTicker(state) + .setContentTitle(context.getString(R.string.tor_provider_setup)) + .setContentText(state); + notificationManager.notify(TOR_SERVICE_NOTIFICATION_ID, notificationBuilder.build()); + } + + + private static NotificationManager initNotificationManager(Context context) { + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + if (notificationManager == null) { + return null; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + createNotificationChannel(notificationManager); + } + return notificationManager; + } + + @TargetApi(26) + private static void createNotificationChannel(NotificationManager notificationManager) { + CharSequence name = "Bitmask Tor Service"; + String description = "Informs about usage of bridges to configure Bitmask."; + NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_NEWSTATUS_ID, + name, + NotificationManager.IMPORTANCE_LOW); + channel.setSound(null, null); + channel.setDescription(description); + notificationManager.createNotificationChannel(channel); + } + + private static NotificationCompat.Builder initNotificationBuilderDefaults(Context context) { + NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_NEWSTATUS_ID); + notificationBuilder. + setDefaults(Notification.DEFAULT_ALL). + setAutoCancel(true); + return notificationBuilder; + } + + public void cancelNotifications(Context context) { + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + if (notificationManager == null) { + return; + } + notificationManager.cancel(TOR_SERVICE_NOTIFICATION_ID); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java new file mode 100644 index 00000000..ed4ae24b --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -0,0 +1,102 @@ +package se.leap.bitmaskclient.tor; + +import android.content.Context; +import android.os.Handler; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.Observable; + +import se.leap.bitmaskclient.R; + +public class TorStatusObservable extends Observable { + + private static final String TAG = TorStatusObservable.class.getSimpleName(); + + public enum TorStatus { + ON, + OFF, + STARTING, + STOPPING, + UNKOWN + } + + private static TorStatusObservable instance; + private TorStatus status = TorStatus.UNKOWN; + private final TorNotificationManager torNotificationManager; + private String lastError; + private int port = -1; + + private TorStatusObservable() { + torNotificationManager = new TorNotificationManager(); + } + + public static TorStatusObservable getInstance() { + if (instance == null) { + instance = new TorStatusObservable(); + } + return instance; + } + + public static TorStatus getStatus() { + return getInstance().status; + } + + + public static void updateState(Context context, String status) { + try { + Log.d(TAG, "update tor state: " + status); + getInstance().status = TorStatus.valueOf(status); + if (getInstance().status == TorStatus.OFF) { + getInstance().torNotificationManager.cancelNotifications(context); + } else { + getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context)); + } + instance.setChanged(); + instance.notifyObservers(); + + + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + + public static void setLastError(String error) { + getInstance().lastError = error; + instance.setChanged(); + instance.notifyObservers(); + } + + public static void setProxyPort(int port) { + getInstance().port = port; + instance.setChanged(); + instance.notifyObservers(); + } + + public static int getProxyPort() { + return getInstance().port; + } + + + @Nullable + public String getLastError() { + return lastError; + } + + private static String getStringForCurrentStatus(Context context) { + switch (getInstance().status) { + case ON: + return context.getString(R.string.tor_started); + case STARTING: + return context.getString(R.string.tor_starting); + case STOPPING: + return context.getString(R.string.tor_stopping); + case OFF: + case UNKOWN: + break; + } + return null; + } +} -- cgit v1.2.3 From a28080ddfe35ac85c7da552739dc27f0687734a2 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 23 Jun 2021 03:36:40 +0200 Subject: don't use hard coded strings --- app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java index 71a2735c..4acc2b7e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java @@ -45,7 +45,7 @@ public class TorNotificationManager { return notificationBuilder .setSmallIcon(R.drawable.ic_bridge_36) .setWhen(System.currentTimeMillis()) - .setContentTitle("Using Bridges to configure provider.").build(); + .setContentTitle(context.getString(R.string.tor_provider_setup)).build(); } public void buildTorNotification(Context context, String state) { -- cgit v1.2.3 From 7325a74661e943fc0f989ef5e230f0862cc8e9fb Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 23 Jun 2021 16:33:54 +0200 Subject: automatically start VPN after switching provider --- app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java | 1 + 1 file changed, 1 insertion(+) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java index 126c4a98..99f6826f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java @@ -202,6 +202,7 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, switch (requestCode) { case REQUEST_CODE_SWITCH_PROVIDER: EipCommand.stopVPN(this.getApplicationContext()); + EipCommand.startVPN(this.getApplicationContext(), false); break; case REQUEST_CODE_CONFIGURE_LEAP: Log.d(TAG, "REQUEST_CODE_CONFIGURE_LEAP - onActivityResult - MainActivity"); -- cgit v1.2.3 From 57915c157c880f29ac9577d1074bf2d54156231f Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 23 Jun 2021 16:35:38 +0200 Subject: automatically close navigation drawer after switch account item was selected --- .../leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java index 5cae1591..f905a7d2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java @@ -289,8 +289,10 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen if (isDefaultBitmask()) { IconTextEntry switchProvider = drawerView.findViewById(R.id.switch_provider); switchProvider.setVisibility(VISIBLE); - switchProvider.setOnClickListener(v -> - getActivity().startActivityForResult(new Intent(getActivity(), ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER)); + switchProvider.setOnClickListener(v -> { + closeDrawer(); + getActivity().startActivityForResult(new Intent(getActivity(), ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); + }); } } -- cgit v1.2.3 From 236c17ec3f4348a9f0d4ec4a2454b9fbfaf8707f Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 24 Jun 2021 23:15:41 +0200 Subject: show tor status info in provider setup activies --- .../activities/ConfigWizardBaseActivity.java | 35 ++++++++++++++++++---- .../providersetup/activities/LoginActivity.java | 2 +- .../providersetup/activities/SignupActivity.java | 2 +- .../bitmaskclient/tor/TorNotificationManager.java | 7 +++-- .../bitmaskclient/tor/TorStatusObservable.java | 2 +- 5 files changed, 36 insertions(+), 12 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java index b2f13e07..7d452200 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java @@ -19,11 +19,14 @@ import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.Guideline; import androidx.core.content.ContextCompat; +import java.util.Observable; +import java.util.Observer; + import butterknife.BindView; -import butterknife.Optional; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.views.ProviderHeaderView; +import se.leap.bitmaskclient.tor.TorStatusObservable; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.view.View.GONE; @@ -37,7 +40,7 @@ import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; * Created by fupduck on 09.01.18. */ -public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity { +public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity implements Observer { private static final String TAG = ConfigWizardBaseActivity.class.getName(); public static final float GUIDE_LINE_COMPACT_DELTA = 0.1f; @@ -55,9 +58,13 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity { @BindView(R.id.progressbar) protected ProgressBar progressBar; + @Nullable + @BindView(R.id.progressbar_title) + protected AppCompatTextView progressbarTitle; + @Nullable @BindView(R.id.progressbar_description) - protected AppCompatTextView progressbarText; + protected AppCompatTextView progressbarDescription; //Only tablet layouts have guidelines as they are based on a ConstraintLayout @Nullable @@ -142,12 +149,15 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity { protected void onPause() { super.onPause(); isActivityShowing = false; + TorStatusObservable.getInstance().deleteObserver(this); } @Override protected void onResume() { super.onResume(); isActivityShowing = true; + TorStatusObservable.getInstance().addObserver(this); + setProgressbarDescription(TorStatusObservable.getStringForCurrentStatus(this)); } protected void restoreState(Bundle savedInstanceState) { @@ -184,11 +194,18 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity { loadingScreen.setVisibility(VISIBLE); } - protected void setProgressbarText(@StringRes int progressbarText) { - if (this.progressbarText == null) { + protected void setProgressbarTitle(@StringRes int progressbarTitle) { + if (this.progressbarTitle == null) { + return; + } + this.progressbarTitle.setText(progressbarTitle); + } + + protected void setProgressbarDescription(String progressbarDescription) { + if (this.progressbarDescription == null) { return; } - this.progressbarText.setText(progressbarText); + this.progressbarDescription.setText(progressbarDescription); } @@ -287,4 +304,10 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity { }); } + @Override + public void update(Observable o, Object arg) { + if (o instanceof TorStatusObservable) { + runOnUiThread(() -> setProgressbarDescription(TorStatusObservable.getStringForCurrentStatus(ConfigWizardBaseActivity.this))); + } + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/LoginActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/LoginActivity.java index a8bac6d8..9a5f31f2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/LoginActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/LoginActivity.java @@ -17,7 +17,7 @@ public class LoginActivity extends ProviderCredentialsBaseActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setProgressbarText(R.string.logging_in); + setProgressbarTitle(R.string.logging_in); setProviderHeaderLogo(R.drawable.logo); setProviderHeaderText(R.string.login_to_profile); } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SignupActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SignupActivity.java index c0245845..16007a70 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SignupActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SignupActivity.java @@ -37,7 +37,7 @@ public class SignupActivity extends ProviderCredentialsBaseActivity { setProviderHeaderLogo(R.drawable.logo); setProviderHeaderText(R.string.create_profile); - setProgressbarText(R.string.signing_up); + setProgressbarTitle(R.string.signing_up); setButtonText(R.string.signup_button); passwordVerificationField.setVisibility(VISIBLE); diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java index 4acc2b7e..71b5c378 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java @@ -27,6 +27,8 @@ import androidx.annotation.NonNull; import androidx.core.app.NotificationCompat; import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.base.models.Provider; +import se.leap.bitmaskclient.base.models.ProviderObservable; public class TorNotificationManager { public final static int TOR_SERVICE_NOTIFICATION_ID = 10; @@ -45,7 +47,7 @@ public class TorNotificationManager { return notificationBuilder .setSmallIcon(R.drawable.ic_bridge_36) .setWhen(System.currentTimeMillis()) - .setContentTitle(context.getString(R.string.tor_provider_setup)).build(); + .setContentTitle(context.getString(R.string.tor_started)).build(); } public void buildTorNotification(Context context, String state) { @@ -58,8 +60,7 @@ public class TorNotificationManager { .setSmallIcon(R.drawable.ic_bridge_36) .setWhen(System.currentTimeMillis()) .setTicker(state) - .setContentTitle(context.getString(R.string.tor_provider_setup)) - .setContentText(state); + .setContentTitle(state); notificationManager.notify(TOR_SERVICE_NOTIFICATION_ID, notificationBuilder.build()); } diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index ed4ae24b..e806e441 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -85,7 +85,7 @@ public class TorStatusObservable extends Observable { return lastError; } - private static String getStringForCurrentStatus(Context context) { + public static String getStringForCurrentStatus(Context context) { switch (getInstance().status) { case ON: return context.getString(R.string.tor_started); -- cgit v1.2.3 From 6f0e9019fcccac9ae5edbaadd91915cb32c867da Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 24 Jun 2021 23:22:00 +0200 Subject: Stop tor proxy if provider api communication failed. Proxy will be reinitiated on next api call --- .../main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java index 45c829b6..f42a7d3d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java @@ -68,7 +68,11 @@ import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_NOK; import static se.leap.bitmaskclient.providersetup.ProviderAPI.STOP_PROXY; import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; @@ -202,6 +206,13 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta case INCORRECTLY_DOWNLOADED_GEOIP_JSON: maybeStartEipService(resultData); break; + case PROVIDER_NOK: + case INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE: + case INCORRECTLY_DOWNLOADED_EIP_SERVICE: + case INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE: + if (TorStatusObservable.getStatus() != OFF) { + ProviderAPICommand.execute(context.getApplicationContext(), STOP_PROXY, null); + } default: break; } -- cgit v1.2.3 From 9687a96f2608be215c6ddcc22f2ecfe6a889093a Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 24 Jun 2021 23:57:48 +0200 Subject: use notifications contentText instead of contentTitle, so that the complete tor notification text can be shown --- .../main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java index 71b5c378..a2401732 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java @@ -47,7 +47,7 @@ public class TorNotificationManager { return notificationBuilder .setSmallIcon(R.drawable.ic_bridge_36) .setWhen(System.currentTimeMillis()) - .setContentTitle(context.getString(R.string.tor_started)).build(); + .setContentText(context.getString(R.string.tor_started)).build(); } public void buildTorNotification(Context context, String state) { @@ -60,7 +60,7 @@ public class TorNotificationManager { .setSmallIcon(R.drawable.ic_bridge_36) .setWhen(System.currentTimeMillis()) .setTicker(state) - .setContentTitle(state); + .setContentText(state); notificationManager.notify(TOR_SERVICE_NOTIFICATION_ID, notificationBuilder.build()); } -- cgit v1.2.3 From aadae76e5641684cf854b6193f3015be0f7a1b0b Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 10 Jul 2021 03:39:10 +0200 Subject: update tor-android --- .../leap/bitmaskclient/tor/IPtProxyInterface.java | 72 ++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyInterface.java (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyInterface.java b/app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyInterface.java new file mode 100644 index 00000000..0203e082 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyInterface.java @@ -0,0 +1,72 @@ +package se.leap.bitmaskclient.tor; + +public interface IPtProxyInterface { + + /** + * StateLocation - Override TOR_PT_STATE_LOCATION, which defaults to "$TMPDIR/pt_state". + */ + void setStateLocation(String v); + + /** + * StateLocation - Override TOR_PT_STATE_LOCATION, which defaults to "$TMPDIR/pt_state". + */ + String getStateLocation(); + + /** + * SnowflakePort - Port where Snowflake will provide its service. + Only use this property after calling StartSnowflake! It might have changed after that! + */ + long snowflakePort(); + + /** + * StartSnowflake - Start the Snowflake client. + + @param ice Comma-separated list of ICE servers. + + @param url URL of signaling broker. + + @param front Front domain. + + @param logFile Name of log file. OPTIONAL + + @param logToStateDir Resolve the log file relative to Tor's PT state dir. + + @param keepLocalAddresses Keep local LAN address ICE candidates. + + @param unsafeLogging Prevent logs from being scrubbed. + + @param maxPeers Capacity for number of multiplexed WebRTC peers. DEFAULTs to 1 if less than that. + + @return Port number where Snowflake will listen on, if no error happens during start up. + */ + long startSnowflake(String ice, String url, String front, String logFile, boolean logToStateDir, boolean keepLocalAddresses, boolean unsafeLogging, long maxPeers); + + /** + * StartSnowflakeProxy - Start the Snowflake proxy. + + @param capacity Maximum concurrent clients. OPTIONAL. Defaults to 10, if 0. + + @param broker Broker URL. OPTIONAL. Defaults to https://snowflake-broker.bamsoftware.com/, if empty. + + @param relay WebSocket relay URL. OPTIONAL. Defaults to wss://snowflake.bamsoftware.com/, if empty. + + @param stun STUN URL. OPTIONAL. Defaults to stun:stun.stunprotocol.org:3478, if empty. + + @param logFile Name of log file. OPTIONAL + + @param keepLocalAddresses Keep local LAN address ICE candidates. + + @param unsafeLogging Prevent logs from being scrubbed. + */ + void startSnowflakeProxy(long capacity, String broker, String relay, String stun, String logFile, boolean keepLocalAddresses, boolean unsafeLogging); + + /** + * StopSnowflake - Stop the Snowflake client. + */ + void stopSnowflake(); + + /** + * StopSnowflakeProxy - Stop the Snowflake proxy. + */ + void stopSnowflakeProxy(); +} -- cgit v1.2.3 From 6a3b5094cbc347bc9119214f8ea074ce53452cdb Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 11 Jul 2021 16:31:30 +0200 Subject: inject IPtProxy in TorService --- .../bitmaskclient/providersetup/ProviderAPI.java | 2 ++ .../se/leap/bitmaskclient/tor/IPtProxyWrapper.java | 40 ++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyWrapper.java (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index dcbe9636..9ba64b31 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -39,6 +39,7 @@ import java.util.concurrent.LinkedBlockingQueue; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator; +import se.leap.bitmaskclient.tor.IPtProxyWrapper; import se.leap.bitmaskclient.tor.TorNotificationManager; import se.leap.bitmaskclient.tor.TorStatusObservable; @@ -202,6 +203,7 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB try { if (torServiceConnection == null) { Log.d(TAG, "serviceConnection is still null"); + TorService.setIPtProxy(new IPtProxyWrapper()); torServiceConnection = new TorServiceConnection(context); } } catch (InterruptedException | IllegalStateException e) { diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyWrapper.java b/app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyWrapper.java new file mode 100644 index 00000000..c7ca165e --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyWrapper.java @@ -0,0 +1,40 @@ +package se.leap.bitmaskclient.tor; + +import IPtProxy.IPtProxy; + +public class IPtProxyWrapper implements IPtProxyInterface { + @Override + public void setStateLocation(String location) { + IPtProxy.setStateLocation(location); + } + + @Override + public String getStateLocation() { + return IPtProxy.getStateLocation(); + } + + @Override + public long snowflakePort() { + return IPtProxy.snowflakePort(); + } + + @Override + public long startSnowflake(String ice, String url, String front, String logFile, boolean logToStateDir, boolean keepLocalAddresses, boolean unsafeLogging, long maxPeers) { + return IPtProxy.startSnowflake(ice, url, front, logFile, logToStateDir, keepLocalAddresses, unsafeLogging, maxPeers); + } + + @Override + public void startSnowflakeProxy(long capacity, String broker, String relay, String stun, String logFile, boolean keepLocalAddresses, boolean unsafeLogging) { + IPtProxy.startSnowflakeProxy(capacity, broker, relay, stun, logFile, keepLocalAddresses, unsafeLogging); + } + + @Override + public void stopSnowflake() { + IPtProxy.stopSnowflake(); + } + + @Override + public void stopSnowflakeProxy() { + IPtProxy.stopSnowflakeProxy(); + } +} -- cgit v1.2.3 From 02d09ff48aed5374e331f2609d27879cd801b9c3 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 11 Jul 2021 19:16:39 +0200 Subject: update tor-android --- .../main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java new file mode 100644 index 00000000..9ed805e4 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java @@ -0,0 +1,4 @@ +package se.leap.bitmaskclient.tor; + +public class ClientTransportPlugin { +} -- cgit v1.2.3 From 8dc39ff8e4684cbd9235824c58a5deb70fb818ee Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 11 Jul 2021 19:25:50 +0200 Subject: implement ClientTransportPluginInterface to start / stop snowflake client for tor --- .../bitmaskclient/providersetup/ProviderAPI.java | 4 +- .../bitmaskclient/tor/ClientTransportPlugin.java | 93 +++++++++++++++++++++- .../leap/bitmaskclient/tor/IPtProxyInterface.java | 72 ----------------- .../se/leap/bitmaskclient/tor/IPtProxyWrapper.java | 40 ---------- 4 files changed, 94 insertions(+), 115 deletions(-) delete mode 100644 app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyInterface.java delete mode 100644 app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyWrapper.java (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index 9ba64b31..f2376568 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -39,7 +39,7 @@ import java.util.concurrent.LinkedBlockingQueue; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator; -import se.leap.bitmaskclient.tor.IPtProxyWrapper; +import se.leap.bitmaskclient.tor.ClientTransportPlugin; import se.leap.bitmaskclient.tor.TorNotificationManager; import se.leap.bitmaskclient.tor.TorStatusObservable; @@ -203,7 +203,7 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB try { if (torServiceConnection == null) { Log.d(TAG, "serviceConnection is still null"); - TorService.setIPtProxy(new IPtProxyWrapper()); + TorService.setClientTransportPlugin(new ClientTransportPlugin(context.getApplicationContext())); torServiceConnection = new TorServiceConnection(context); } } catch (InterruptedException | IllegalStateException e) { diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java index 9ed805e4..9e3828de 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java @@ -1,4 +1,95 @@ package se.leap.bitmaskclient.tor; -public class ClientTransportPlugin { +import android.content.Context; +import android.util.Log; + +import androidx.annotation.Nullable; + +import org.torproject.jni.ClientTransportPluginInterface; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.ref.WeakReference; +import java.util.HashMap; + +import IPtProxy.IPtProxy; + +public class ClientTransportPlugin implements ClientTransportPluginInterface { + public static String TAG = ClientTransportPlugin.class.getSimpleName(); + + private HashMap mFronts; + private final WeakReference contextRef; + private long snowflakePort = -1; + + public ClientTransportPlugin(Context context) { + this.contextRef = new WeakReference<>(context); + loadCdnFronts(context); + } + + @Override + public void start() { + Context context = contextRef.get(); + if (context == null) { + return; + } + File logfile = new File(context.getApplicationContext().getCacheDir(), "snowflake.log"); + Log.d(TAG, "logfile at " + logfile.getAbsolutePath()); + if (!logfile.exists()) { + try { + logfile.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + //this is using the current, default Tor snowflake infrastructure + String target = getCdnFront("snowflake-target"); + String front = getCdnFront("snowflake-front"); + String stunServer = getCdnFront("snowflake-stun"); + Log.d(TAG, "startSnowflake. target: " + target + ", front:" + front + ", stunServer" + stunServer); + snowflakePort = IPtProxy.startSnowflake( stunServer, target, front, logfile.getAbsolutePath(), false, false, true, 1); + Log.d(TAG, "startSnowflake running on port: " + snowflakePort); + } + + @Override + public void stop() { + IPtProxy.stopSnowflake(); + snowflakePort = -1; + } + + @Override + public String getTorrc() { + return "UseBridges 1\n" + + "ClientTransportPlugin snowflake socks5 127.0.0.1:" + snowflakePort + "\n" + + "Bridge snowflake 192.0.2.3:1"; + } + + private void loadCdnFronts(Context context) { + if (mFronts == null) { + mFronts = new HashMap<>(); + } + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(context.getAssets().open("fronts"))); + String line; + while (true) { + line = reader.readLine(); + if (line == null) break; + String[] front = line.split(" "); + mFronts.put(front[0], front[1]); + Log.d(TAG, "front: " + front[0] + ", " + front[1]); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Nullable + private String getCdnFront(String service) { + if (mFronts != null) { + return mFronts.get(service); + } + return null; + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyInterface.java b/app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyInterface.java deleted file mode 100644 index 0203e082..00000000 --- a/app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyInterface.java +++ /dev/null @@ -1,72 +0,0 @@ -package se.leap.bitmaskclient.tor; - -public interface IPtProxyInterface { - - /** - * StateLocation - Override TOR_PT_STATE_LOCATION, which defaults to "$TMPDIR/pt_state". - */ - void setStateLocation(String v); - - /** - * StateLocation - Override TOR_PT_STATE_LOCATION, which defaults to "$TMPDIR/pt_state". - */ - String getStateLocation(); - - /** - * SnowflakePort - Port where Snowflake will provide its service. - Only use this property after calling StartSnowflake! It might have changed after that! - */ - long snowflakePort(); - - /** - * StartSnowflake - Start the Snowflake client. - - @param ice Comma-separated list of ICE servers. - - @param url URL of signaling broker. - - @param front Front domain. - - @param logFile Name of log file. OPTIONAL - - @param logToStateDir Resolve the log file relative to Tor's PT state dir. - - @param keepLocalAddresses Keep local LAN address ICE candidates. - - @param unsafeLogging Prevent logs from being scrubbed. - - @param maxPeers Capacity for number of multiplexed WebRTC peers. DEFAULTs to 1 if less than that. - - @return Port number where Snowflake will listen on, if no error happens during start up. - */ - long startSnowflake(String ice, String url, String front, String logFile, boolean logToStateDir, boolean keepLocalAddresses, boolean unsafeLogging, long maxPeers); - - /** - * StartSnowflakeProxy - Start the Snowflake proxy. - - @param capacity Maximum concurrent clients. OPTIONAL. Defaults to 10, if 0. - - @param broker Broker URL. OPTIONAL. Defaults to https://snowflake-broker.bamsoftware.com/, if empty. - - @param relay WebSocket relay URL. OPTIONAL. Defaults to wss://snowflake.bamsoftware.com/, if empty. - - @param stun STUN URL. OPTIONAL. Defaults to stun:stun.stunprotocol.org:3478, if empty. - - @param logFile Name of log file. OPTIONAL - - @param keepLocalAddresses Keep local LAN address ICE candidates. - - @param unsafeLogging Prevent logs from being scrubbed. - */ - void startSnowflakeProxy(long capacity, String broker, String relay, String stun, String logFile, boolean keepLocalAddresses, boolean unsafeLogging); - - /** - * StopSnowflake - Stop the Snowflake client. - */ - void stopSnowflake(); - - /** - * StopSnowflakeProxy - Stop the Snowflake proxy. - */ - void stopSnowflakeProxy(); -} diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyWrapper.java b/app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyWrapper.java deleted file mode 100644 index c7ca165e..00000000 --- a/app/src/main/java/se/leap/bitmaskclient/tor/IPtProxyWrapper.java +++ /dev/null @@ -1,40 +0,0 @@ -package se.leap.bitmaskclient.tor; - -import IPtProxy.IPtProxy; - -public class IPtProxyWrapper implements IPtProxyInterface { - @Override - public void setStateLocation(String location) { - IPtProxy.setStateLocation(location); - } - - @Override - public String getStateLocation() { - return IPtProxy.getStateLocation(); - } - - @Override - public long snowflakePort() { - return IPtProxy.snowflakePort(); - } - - @Override - public long startSnowflake(String ice, String url, String front, String logFile, boolean logToStateDir, boolean keepLocalAddresses, boolean unsafeLogging, long maxPeers) { - return IPtProxy.startSnowflake(ice, url, front, logFile, logToStateDir, keepLocalAddresses, unsafeLogging, maxPeers); - } - - @Override - public void startSnowflakeProxy(long capacity, String broker, String relay, String stun, String logFile, boolean keepLocalAddresses, boolean unsafeLogging) { - IPtProxy.startSnowflakeProxy(capacity, broker, relay, stun, logFile, keepLocalAddresses, unsafeLogging); - } - - @Override - public void stopSnowflake() { - IPtProxy.stopSnowflake(); - } - - @Override - public void stopSnowflakeProxy() { - IPtProxy.stopSnowflakeProxy(); - } -} -- cgit v1.2.3 From 3d9e76779f102b5cbbb29a2215415ab1a7f96aed Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 14 Jul 2021 23:53:26 +0200 Subject: stop torService immediately instead of queueing it in provider api service --- .../se/leap/bitmaskclient/eip/EipSetupObserver.java | 7 ++++--- .../leap/bitmaskclient/providersetup/ProviderAPI.java | 11 ----------- .../providersetup/ProviderApiManagerBase.java | 6 +----- .../activities/ProviderSetupBaseActivity.java | 19 +++++++++++++++---- 4 files changed, 20 insertions(+), 23 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java index f42a7d3d..1a2d8769 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java @@ -73,7 +73,6 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLO import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_NOK; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.STOP_PROXY; import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; /** @@ -211,7 +210,8 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta case INCORRECTLY_DOWNLOADED_EIP_SERVICE: case INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE: if (TorStatusObservable.getStatus() != OFF) { - ProviderAPICommand.execute(context.getApplicationContext(), STOP_PROXY, null); + Intent stopIntent = new Intent(context, TorService.class); + context.stopService(stopIntent); } default: break; @@ -360,7 +360,8 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta observedProfileFromVpnStatus = null; this.changingGateway.set(changingGateway); if (TorStatusObservable.getStatus() != OFF) { - ProviderAPICommand.execute(context.getApplicationContext(), STOP_PROXY, null); + Intent intent = new Intent(context, TorService.class); + context.stopService(intent); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index f2376568..f88f44a5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -174,17 +174,6 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB return -1; } - @Override - public void stopTorConnection() { - if (TorStatusObservable.getStatus() != OFF) { - TorStatusObservable.updateState(this, STOPPING.toString()); - initTorServiceConnection(this); - if (torServiceConnection != null) { - torServiceConnection.torService.stopSelf(); - } - } - } - private ProviderApiManager initApiManager() { SharedPreferences preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); OkHttpClientGenerator clientGenerator = new OkHttpClientGenerator(getResources()); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 8118c872..00cbcd3e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -149,8 +149,7 @@ public abstract class ProviderApiManagerBase { public interface ProviderApiServiceCallback { void broadcastEvent(Intent intent); - int initTorConnection(); - void stopTorConnection(); + int getTorHttpTunnelPort(); } private final ProviderApiServiceCallback serviceCallback; @@ -286,9 +285,6 @@ public abstract class ProviderApiManagerBase { ProviderObservable.getInstance().setProviderForDns(null); } break; - case STOP_PROXY: - serviceCallback.stopTorConnection(); - break; } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java index 40efd811..0297bc39 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java @@ -29,6 +29,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.json.JSONException; import org.json.JSONObject; +import org.torproject.jni.TorService; import se.leap.bitmaskclient.base.FragmentManagerEnhanced; import se.leap.bitmaskclient.base.models.Provider; @@ -38,6 +39,7 @@ import se.leap.bitmaskclient.providersetup.ProviderApiSetupBroadcastReceiver; import se.leap.bitmaskclient.providersetup.ProviderManager; import se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog; import se.leap.bitmaskclient.providersetup.ProviderSetupInterface; +import se.leap.bitmaskclient.tor.TorStatusObservable; import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_PROVIDER_API_EVENT; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; @@ -51,6 +53,7 @@ import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.Provide import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER; import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.SHOWING_PROVIDER_DETAILS; import static se.leap.bitmaskclient.providersetup.ProviderSetupInterface.ProviderConfigState.SHOW_FAILED_DIALOG; +import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; /** * Created by cyberta on 19.08.18. @@ -90,7 +93,7 @@ public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity } else if (SHOW_FAILED_DIALOG == providerConfigState) { showProgressBar(); } else if (SHOWING_PROVIDER_DETAILS == providerConfigState) { - cancelSettingUpProvider(); + cancelSettingUpProvider(false); } else if (PENDING_SHOW_PROVIDER_DETAILS == providerConfigState) { showProviderDetails(); } @@ -156,9 +159,7 @@ public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity // -------- DownloadFailedDialogInterface ---v @Override public void cancelSettingUpProvider() { - providerConfigState = PROVIDER_NOT_SET; - provider = null; - hideProgressBar(); + cancelSettingUpProvider(true); } @Override @@ -167,6 +168,16 @@ public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity ProviderAPICommand.execute(this, UPDATE_PROVIDER_DETAILS, provider); } + public void cancelSettingUpProvider(boolean stopTor) { + if (stopTor && TorStatusObservable.getStatus() != OFF) { + Intent torServiceIntent = new Intent(getApplicationContext(), TorService.class); + stopService(torServiceIntent); + } + providerConfigState = PROVIDER_NOT_SET; + provider = null; + hideProgressBar(); + } + protected void restoreState(Bundle savedInstanceState) { super.restoreState(savedInstanceState); if (savedInstanceState == null) { -- cgit v1.2.3 From 9d16ae1456b6d6a2fc2eb67b23fc05bc878ba741 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 14 Jul 2021 23:55:21 +0200 Subject: minor language fixes in ProviderSetupBaseActivity --- .../providersetup/activities/ProviderSetupBaseActivity.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java index 0297bc39..e4569c51 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java @@ -34,8 +34,8 @@ import org.torproject.jni.TorService; import se.leap.bitmaskclient.base.FragmentManagerEnhanced; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.providersetup.ProviderAPICommand; -import se.leap.bitmaskclient.providersetup.ProviderDetailActivity; import se.leap.bitmaskclient.providersetup.ProviderApiSetupBroadcastReceiver; +import se.leap.bitmaskclient.providersetup.ProviderDetailActivity; import se.leap.bitmaskclient.providersetup.ProviderManager; import se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog; import se.leap.bitmaskclient.providersetup.ProviderSetupInterface; @@ -60,7 +60,7 @@ import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; */ public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity implements ProviderSetupInterface, ProviderSetupFailedDialog.DownloadFailedDialogInterface { - final public static String TAG = "PoviderSetupActivity"; + final public static String TAG = "ProviderSetupActivity"; final private static String ACTIVITY_STATE = "ACTIVITY STATE"; final private static String REASON_TO_FAIL = "REASON TO FAIL"; @@ -207,7 +207,7 @@ public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity /** * Once selected a provider, this fragment offers the user to log in, * use it anonymously (if possible) - * or cancel his/her election pressing the back button. + * or cancel their selection pressing the back button. */ public void showProviderDetails() { // show only if current activity is shown -- cgit v1.2.3 From 99fd84e800758647b4a4e178f8f5f7112b54d66f Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 14 Jul 2021 23:59:34 +0200 Subject: rename method --- app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java | 2 +- .../se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index f88f44a5..15843697 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -154,7 +154,7 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB @Override - public int initTorConnection() { + public int getTorHttpTunnelPort() { initTorServiceConnection(this); if (torServiceConnection != null) { Intent torServiceIntent = new Intent(this, TorService.class); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 00cbcd3e..f70be365 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -291,7 +291,7 @@ public abstract class ProviderApiManagerBase { protected int startTorProxy() { int port = -1; if (PreferenceHelper.useTor(preferences) && EipStatus.getInstance().isDisconnected() ) { - port = serviceCallback.initTorConnection(); + port = serviceCallback.getTorHttpTunnelPort(); if (port != -1) { try { waitForTorCircuits(); -- cgit v1.2.3 From 3c15fc1fb3cfb1537e2dfad740921c5f1d063259 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 15 Jul 2021 00:02:37 +0200 Subject: remove log in ProviderApiManagerBase --- .../java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java | 1 - 1 file changed, 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index f70be365..0fcbcdae 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -166,7 +166,6 @@ public abstract class ProviderApiManagerBase { } public void handleIntent(Intent command) { -// Log.d(TAG, "handleIntent was called!"); ResultReceiver receiver = null; if (command.getParcelableExtra(RECEIVER_KEY) != null) { receiver = command.getParcelableExtra(RECEIVER_KEY); -- cgit v1.2.3 From aa43298684367000cadf16037cb90c366ac3c000 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 15 Jul 2021 00:04:36 +0200 Subject: ensure that response.body().close() is always called when reading non-null API responses --- .../bitmaskclient/providersetup/ProviderApiConnector.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiConnector.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiConnector.java index c863abd4..35ad9cd2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiConnector.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiConnector.java @@ -95,10 +95,15 @@ public class ProviderApiConnector { if (!response.isSuccessful()) { VpnStatus.logWarning("[API] API request failed: " + url); } - InputStream inputStream = response.body().byteStream(); - Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"); - if (scanner.hasNext()) { - return scanner.next(); + + if (response.body() != null) { + InputStream inputStream = response.body().byteStream(); + Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"); + if (scanner.hasNext()) { + String result = scanner.next(); + response.body().close(); + return result; + } } return null; } -- cgit v1.2.3 From b2705ea702a9eaa4a0f5566ed70cdfb4f41390d3 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 15 Jul 2021 00:06:24 +0200 Subject: don't set a new ClientTransportPlugin everytime a service connection has been initiated with TorService --- .../main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index 15843697..15e77576 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -192,7 +192,9 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB try { if (torServiceConnection == null) { Log.d(TAG, "serviceConnection is still null"); - TorService.setClientTransportPlugin(new ClientTransportPlugin(context.getApplicationContext())); + if (!TorService.hasClientTransportPlugin()) { + TorService.setClientTransportPlugin(new ClientTransportPlugin(context.getApplicationContext())); + } torServiceConnection = new TorServiceConnection(context); } } catch (InterruptedException | IllegalStateException e) { -- cgit v1.2.3 From a3ed9483391ef38ee6665be4e4fe25a71b4c83be Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 15 Jul 2021 00:08:45 +0200 Subject: always stop tor service connection immediately after we got the http tunnel port --- .../main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index 15e77576..322bf1cd 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -168,7 +168,10 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB getApplicationContext().startService(torServiceIntent); } - return torServiceConnection.torService.getHttpTunnelPort(); + int tunnelPort = torServiceConnection.torService.getHttpTunnelPort(); + torServiceConnection.close(); + torServiceConnection = null; + return tunnelPort; } return -1; -- cgit v1.2.3 From 818281a7fdf8b43437e14478a2276dc821b69284 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 15 Jul 2021 00:10:15 +0200 Subject: set torService to null when tor service connection disconnected --- app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java | 1 + 1 file changed, 1 insertion(+) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index 322bf1cd..42ded09f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -243,6 +243,7 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB @Override public void onServiceDisconnected(ComponentName name) { + torService = null; } }; Intent intent = new Intent(context, TorService.class); -- cgit v1.2.3 From 3d5675f2287f22c399d9a5f4bfcef999100a1b2c Mon Sep 17 00:00:00 2001 From: cyberta Date: Wed, 4 Aug 2021 10:36:56 +0200 Subject: update import path for shapeshifter lib --- .../java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java index d39f8bf3..c7893249 100644 --- a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java @@ -27,7 +27,7 @@ import java.util.Observer; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.eip.EipStatus; -import shapeshifter.ShapeShifter; +import shapeShifter.ShapeShifter; public class Shapeshifter implements Observer { @@ -43,7 +43,7 @@ public class Shapeshifter implements Observer { private int retry = 0; private Handler reconnectHandler; - public class ShapeshifterLogger implements shapeshifter.Logger { + public class ShapeshifterLogger implements shapeShifter.Logger { @Override public void log(String s) { Log.e(TAG, "SHAPESHIFTER ERROR: " + s); -- cgit v1.2.3 From 2da4c19827ed722f4dde2830bd84b21553a13bcd Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 30 Sep 2021 14:50:11 +0200 Subject: set tor setup timeout to 3 minutes --- .../se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 0fcbcdae..b7108225 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -314,7 +314,7 @@ public abstract class ProviderApiManagerBase { } }; TorStatusObservable.getInstance().addObserver(observer); - countDownLatch.await(90, TimeUnit.SECONDS); + countDownLatch.await(180, TimeUnit.SECONDS); } void resetProviderDetails(Provider provider) { -- cgit v1.2.3 From 780c63fc4afbe38eca70237e07165d88596b3843 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 30 Sep 2021 14:50:29 +0200 Subject: remove tor circuit setup observer once timeout reached or tor circuits have been setup successfully --- .../java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java | 1 + 1 file changed, 1 insertion(+) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index b7108225..9ca4c746 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -315,6 +315,7 @@ public abstract class ProviderApiManagerBase { }; TorStatusObservable.getInstance().addObserver(observer); countDownLatch.await(180, TimeUnit.SECONDS); + TorStatusObservable.getInstance().deleteObserver(observer); } void resetProviderDetails(Provider provider) { -- cgit v1.2.3 From c8a6822c27210eba74299718679db101a6ee273e Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 30 Sep 2021 16:08:57 +0200 Subject: workaround for jni issue again --- .../se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java index c7893249..828b90ba 100644 --- a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java @@ -27,7 +27,7 @@ import java.util.Observer; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.eip.EipStatus; -import shapeShifter.ShapeShifter; +import shapeShifter.ShapeShifter_; public class Shapeshifter implements Observer { @@ -37,11 +37,11 @@ public class Shapeshifter implements Observer { private static final int RETRY_TIME = 4000; private static final String TAG = Shapeshifter.class.getSimpleName(); - private ShapeShifter shapeShifter; + private final ShapeShifter_ shapeShifter; private boolean isErrorHandling; private boolean noNetwork; private int retry = 0; - private Handler reconnectHandler; + private final Handler reconnectHandler; public class ShapeshifterLogger implements shapeShifter.Logger { @Override @@ -61,7 +61,7 @@ public class Shapeshifter implements Observer { } public Shapeshifter(Obfs4Options options) { - shapeShifter = new ShapeShifter(); + shapeShifter = new ShapeShifter_(); shapeShifter.setLogger(new ShapeshifterLogger()); setup(options); Looper.prepare(); -- cgit v1.2.3 From 80bf751141c85316c22a0d16c1e4d6fa0f473f44 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 2 Oct 2021 13:31:36 +0200 Subject: * refactor startTorProxy() * fix setting http proxy port correctly * snowflake+tor does currently only work when being connected to a wifi, not a cellular network. For now, we check if the device is connected to a wifi, before attempting to start tor --- .../bitmaskclient/providersetup/ProviderAPI.java | 34 ++++++++++-------- .../providersetup/ProviderApiManagerBase.java | 41 ++++++++++++++-------- 2 files changed, 46 insertions(+), 29 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index 42ded09f..e818f587 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -37,17 +37,15 @@ import java.io.Closeable; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; +import de.blinkt.openvpn.core.NetworkUtils; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator; import se.leap.bitmaskclient.tor.ClientTransportPlugin; import se.leap.bitmaskclient.tor.TorNotificationManager; -import se.leap.bitmaskclient.tor.TorStatusObservable; import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread; import static se.leap.bitmaskclient.tor.TorNotificationManager.TOR_SERVICE_NOTIFICATION_ID; -import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; -import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.STOPPING; /** * Implements HTTP api methods (encapsulated in {{@link ProviderApiManager}}) @@ -151,23 +149,31 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } + @Override + public boolean isConnectedToWifi() { + return NetworkUtils.isConnectedToWifi(getApplicationContext()); + } + + @Override + public void startTorService() { + initTorServiceConnection(this); + Intent torServiceIntent = new Intent(this, TorService.class); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Notification notification = TorNotificationManager.buildTorForegroundNotification(getApplicationContext()); + //noinspection NewApi + getApplicationContext().startForegroundService(torServiceIntent); + torServiceConnection.torService.startForeground(TOR_SERVICE_NOTIFICATION_ID, notification); + } else { + getApplicationContext().startService(torServiceIntent); + } + } @Override public int getTorHttpTunnelPort() { initTorServiceConnection(this); if (torServiceConnection != null) { - Intent torServiceIntent = new Intent(this, TorService.class); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - Notification notification = TorNotificationManager.buildTorForegroundNotification(getApplicationContext()); - //noinspection NewApi - getApplicationContext().startForegroundService(torServiceIntent); - torServiceConnection.torService.startForeground(TOR_SERVICE_NOTIFICATION_ID, notification); - } else { - getApplicationContext().startService(torServiceIntent); - } - int tunnelPort = torServiceConnection.torService.getHttpTunnelPort(); torServiceConnection.close(); torServiceConnection = null; diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 9ca4c746..780ecaed 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -51,6 +51,8 @@ import java.util.NoSuchElementException; import java.util.Observer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLPeerUnverifiedException; @@ -149,7 +151,9 @@ public abstract class ProviderApiManagerBase { public interface ProviderApiServiceCallback { void broadcastEvent(Intent intent); + void startTorService(); int getTorHttpTunnelPort(); + boolean isConnectedToWifi(); } private final ProviderApiServiceCallback serviceCallback; @@ -188,7 +192,11 @@ public abstract class ProviderApiManagerBase { } // uncomment for testing --v - TorStatusObservable.setProxyPort(startTorProxy()); + /* try { + startTorProxy(); + } catch (InterruptedException | TimeoutException e) { + e.printStackTrace(); + } */ Bundle result = new Bundle(); switch (action) { @@ -287,35 +295,38 @@ public abstract class ProviderApiManagerBase { } } - protected int startTorProxy() { - int port = -1; - if (PreferenceHelper.useTor(preferences) && EipStatus.getInstance().isDisconnected() ) { - port = serviceCallback.getTorHttpTunnelPort(); - if (port != -1) { - try { - waitForTorCircuits(); - } catch (InterruptedException e) { - e.printStackTrace(); - port = -1; - } - } + protected boolean startTorProxy() throws InterruptedException, TimeoutException { + if (PreferenceHelper.useTor(preferences) && + EipStatus.getInstance().isDisconnected() && + serviceCallback.isConnectedToWifi() + ) { + serviceCallback.startTorService(); + waitForTorCircuits(); + int port = serviceCallback.getTorHttpTunnelPort(); + TorStatusObservable.setProxyPort(port); + return port != -1; } - return port; + return false; } - private void waitForTorCircuits() throws InterruptedException { + private void waitForTorCircuits() throws InterruptedException, TimeoutException { if (TorStatusObservable.getStatus() == ON) { return; } CountDownLatch countDownLatch = new CountDownLatch(1); + AtomicBoolean successfulSetup = new AtomicBoolean(false); Observer observer = (o, arg) -> { if (TorStatusObservable.getStatus() == ON) { + successfulSetup.set(true); countDownLatch.countDown(); } }; TorStatusObservable.getInstance().addObserver(observer); countDownLatch.await(180, TimeUnit.SECONDS); TorStatusObservable.getInstance().deleteObserver(observer); + if (!successfulSetup.get()) { + throw new TimeoutException("Timeout reached"); + } } void resetProviderDetails(Provider provider) { -- cgit v1.2.3 From cdd97d8bcc65ad80ed1060b297650b8350b27a56 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 2 Oct 2021 13:36:31 +0200 Subject: add log to see if a fetch was successful --- app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java index 1a2d8769..a71a5613 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java @@ -73,6 +73,7 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLO import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_NOK; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_OK; import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; /** @@ -213,6 +214,11 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta Intent stopIntent = new Intent(context, TorService.class); context.stopService(stopIntent); } + Log.d(TAG, "PROVIDER NOK - FETCH FAILED"); + break; + case PROVIDER_OK: + Log.d(TAG, "PROVIDER OK - FETCH SUCCESSFUL"); + break; default: break; } -- cgit v1.2.3 From 0f39fcfc827404a58153941d7ce1b57d272f56d7 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 2 Oct 2021 15:16:05 +0200 Subject: show snowflake logs in logcat --- .../bitmaskclient/tor/ClientTransportPlugin.java | 48 +++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java index 9e3828de..d0385d1e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java @@ -1,6 +1,7 @@ package se.leap.bitmaskclient.tor; import android.content.Context; +import android.os.FileObserver; import android.util.Log; import androidx.annotation.Nullable; @@ -9,10 +10,14 @@ import org.torproject.jni.ClientTransportPluginInterface; import java.io.BufferedReader; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.lang.ref.WeakReference; +import java.util.Collection; import java.util.HashMap; +import java.util.Scanner; +import java.util.Vector; import IPtProxy.IPtProxy; @@ -22,6 +27,7 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { private HashMap mFronts; private final WeakReference contextRef; private long snowflakePort = -1; + private FileObserver logFileObserver; public ClientTransportPlugin(Context context) { this.contextRef = new WeakReference<>(context); @@ -36,12 +42,13 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { } File logfile = new File(context.getApplicationContext().getCacheDir(), "snowflake.log"); Log.d(TAG, "logfile at " + logfile.getAbsolutePath()); - if (!logfile.exists()) { - try { - logfile.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); + try { + if (logfile.exists()) { + logfile.delete(); } + logfile.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); } //this is using the current, default Tor snowflake infrastructure @@ -51,12 +58,43 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { Log.d(TAG, "startSnowflake. target: " + target + ", front:" + front + ", stunServer" + stunServer); snowflakePort = IPtProxy.startSnowflake( stunServer, target, front, logfile.getAbsolutePath(), false, false, true, 1); Log.d(TAG, "startSnowflake running on port: " + snowflakePort); + watchLogFile(logfile); + } + + private void watchLogFile(File logfile) { + final Vector lastBuffer = new Vector<>(); + logFileObserver = new FileObserver(logfile) { + @Override + public void onEvent(int event, @Nullable String name) { + if (FileObserver.MODIFY == event) { + try (Scanner scanner = new Scanner(logfile)) { + Vector currentBuffer = new Vector<>(); + while (scanner.hasNextLine()) { + currentBuffer.add(scanner.nextLine()); + } + if (lastBuffer.size() < currentBuffer.size()) { + int startIndex = lastBuffer.size() > 0 ? lastBuffer.size() - 1 : 0; + int endIndex = currentBuffer.size() - 1; + Collection newMessages = currentBuffer.subList(startIndex, endIndex); + for (String message : newMessages) { + Log.d("[SNOWFLAKE]", message); + } + lastBuffer.addAll(newMessages); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + } + }; + logFileObserver.startWatching(); } @Override public void stop() { IPtProxy.stopSnowflake(); snowflakePort = -1; + logFileObserver.stopWatching(); } @Override -- cgit v1.2.3 From 1d6bdaf993b2235f7ebc7ca9d2f3ebc5dee8c9cc Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 2 Oct 2021 15:18:32 +0200 Subject: set max snowflake peers to 5 for now --- app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java index d0385d1e..0fd51d15 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java @@ -56,7 +56,7 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { String front = getCdnFront("snowflake-front"); String stunServer = getCdnFront("snowflake-stun"); Log.d(TAG, "startSnowflake. target: " + target + ", front:" + front + ", stunServer" + stunServer); - snowflakePort = IPtProxy.startSnowflake( stunServer, target, front, logfile.getAbsolutePath(), false, false, true, 1); + snowflakePort = IPtProxy.startSnowflake( stunServer, target, front, logfile.getAbsolutePath(), false, false, true, 5); Log.d(TAG, "startSnowflake running on port: " + snowflakePort); watchLogFile(logfile); } -- cgit v1.2.3 From dac7d9ce22f1eb2a96cc8a3a0fc34e6c3d4c9291 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 16 Oct 2021 11:56:25 +0200 Subject: update shapeshifter jni bindings --- .../se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java index 828b90ba..970703cc 100644 --- a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java @@ -27,7 +27,7 @@ import java.util.Observer; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.eip.EipStatus; -import shapeShifter.ShapeShifter_; +import shapeshifter.ShapeShifter; public class Shapeshifter implements Observer { @@ -37,13 +37,13 @@ public class Shapeshifter implements Observer { private static final int RETRY_TIME = 4000; private static final String TAG = Shapeshifter.class.getSimpleName(); - private final ShapeShifter_ shapeShifter; + private final shapeshifter.ShapeShifter shapeShifter; private boolean isErrorHandling; private boolean noNetwork; private int retry = 0; private final Handler reconnectHandler; - public class ShapeshifterLogger implements shapeShifter.Logger { + public class ShapeshifterLogger implements shapeshifter.Logger { @Override public void log(String s) { Log.e(TAG, "SHAPESHIFTER ERROR: " + s); @@ -61,7 +61,7 @@ public class Shapeshifter implements Observer { } public Shapeshifter(Obfs4Options options) { - shapeShifter = new ShapeShifter_(); + shapeShifter = new ShapeShifter(); shapeShifter.setLogger(new ShapeshifterLogger()); setup(options); Looper.prepare(); -- cgit v1.2.3 From fcec92a0042477347338a25cd072d622edfa03c9 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 16 Oct 2021 11:59:42 +0200 Subject: show tor bootstrapping progress in notifications --- .../leap/bitmaskclient/eip/EipSetupObserver.java | 4 +- .../bitmaskclient/tor/TorNotificationManager.java | 13 +++- .../bitmaskclient/tor/TorStatusObservable.java | 77 +++++++++++++++++++++- 3 files changed, 87 insertions(+), 7 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java index a71a5613..23fbdc0c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java @@ -169,7 +169,9 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta private void handleTorStatusEvent(Intent intent) { String status = intent.getStringExtra(TorService.EXTRA_STATUS); Log.d(TAG, "handle Tor status event: " + status); - TorStatusObservable.updateState(context, status); + Integer bootstrap = intent.getIntExtra(TorService.EXTRA_STATUS_DETAIL_BOOTSTRAP, -1); + String logKey = intent.getStringExtra(TorService.EXTRA_STATUS_DETAIL_LOGKEY); + TorStatusObservable.updateState(context, status, bootstrap, logKey); } diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java index a2401732..8148fd94 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java @@ -50,7 +50,7 @@ public class TorNotificationManager { .setContentText(context.getString(R.string.tor_started)).build(); } - public void buildTorNotification(Context context, String state) { + public void buildTorNotification(Context context, String state, String message, int progress) { NotificationManager notificationManager = initNotificationManager(context); if (notificationManager == null) { return; @@ -59,8 +59,15 @@ public class TorNotificationManager { notificationBuilder .setSmallIcon(R.drawable.ic_bridge_36) .setWhen(System.currentTimeMillis()) - .setTicker(state) - .setContentText(state); + .setStyle(new NotificationCompat.BigTextStyle(). + setBigContentTitle(state). + bigText(message)) + .setTicker(message) + .setContentTitle(state) + .setContentText(message); + if (progress > 0) { + notificationBuilder.setProgress(100, progress, false); + } notificationManager.notify(TOR_SERVICE_NOTIFICATION_ID, notificationBuilder.build()); } diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index e806e441..11baecbf 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -8,6 +8,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.util.Observable; +import java.util.Vector; import se.leap.bitmaskclient.R; @@ -28,6 +29,8 @@ public class TorStatusObservable extends Observable { private final TorNotificationManager torNotificationManager; private String lastError; private int port = -1; + private int bootstrapPercent = -1; + private Vector lastLogs = new Vector<>(100); private TorStatusObservable() { torNotificationManager = new TorNotificationManager(); @@ -44,25 +47,93 @@ public class TorStatusObservable extends Observable { return getInstance().status; } + public static void logMessage(Context context, String tag, String message) { + Log.d(tag, message); + addLog(message); + if (getInstance().status != TorStatus.OFF) { + getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), message, getInstance().bootstrapPercent); + } + instance.setChanged(); + instance.notifyObservers(); + } + + private static void addLog(String message) { + if (instance.lastLogs.size() > 100) { + instance.lastLogs.remove(0); + } + instance.lastLogs.add(message); + } public static void updateState(Context context, String status) { + updateState(context,status, -1, null); + } + + public static void updateState(Context context, String status, int bootstrapPercent, @Nullable String logKey) { try { - Log.d(TAG, "update tor state: " + status); + Log.d(TAG, "update tor state: " + status + " " + bootstrapPercent + " "+ logKey); getInstance().status = TorStatus.valueOf(status); + if (bootstrapPercent != -1) { + getInstance().bootstrapPercent = bootstrapPercent; + } + int progress = getInstance().status == TorStatus.STARTING ? getInstance().bootstrapPercent : -1; + + if (getInstance().status == TorStatus.OFF) { getInstance().torNotificationManager.cancelNotifications(context); + } else if (logKey != null) { + String log = getStringFor(context, logKey); + addLog(log); + getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), log, progress); } else { - getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context)); + String log = instance.lastLogs.size() > 0 ? instance.lastLogs.lastElement() : ""; + getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), log, progress); } + instance.setChanged(); instance.notifyObservers(); - } catch (IllegalStateException e) { e.printStackTrace(); } } + private static String getStringFor(Context context, String key) { + switch (key) { + case "conn_pt": + return context.getString(R.string.log_conn_pt); + case "conn_done_pt": + return context.getString(R.string.log_conn_done_pt); + case "conn_done": + return context.getString(R.string.log_conn_done); + case "handshake": + return context.getString(R.string.log_handshake); + case "handshake_done": + return context.getString(R.string.log_handshake_done); + case "onehop_create": + return context.getString(R.string.log_onehop_create); + case "requesting_status": + return context.getString(R.string.log_requesting_status); + case "loading_status": + return context.getString(R.string.log_loading_status); + case "loading_keys": + return context.getString(R.string.log_loading_keys); + case "requesting_descriptors": + return context.getString(R.string.log_requesting_desccriptors); + case "loading_descriptors": + return context.getString(R.string.log_loading_descriptors); + case "enough_dirinfo": + return context.getString(R.string.log_enough_dirinfo); + case "ap_handshake_done": + return context.getString(R.string.log_ap_handshake_done); + case "circuit_create": + return context.getString(R.string.log_circuit_create); + case "done": + return context.getString(R.string.log_done); + default: + return key; + } + } + public static void setLastError(String error) { getInstance().lastError = error; instance.setChanged(); -- cgit v1.2.3 From bb2f6caa4ed2fae8978c578be829dcc6b08d542b Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 16 Oct 2021 13:52:03 +0200 Subject: show snowflake logs in notification --- .../bitmaskclient/tor/ClientTransportPlugin.java | 24 ++++++++++++- .../bitmaskclient/tor/TorStatusObservable.java | 42 +++++++++++++++------- 2 files changed, 52 insertions(+), 14 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java index 0fd51d15..1d2b7cea 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java @@ -18,6 +18,8 @@ import java.util.Collection; import java.util.HashMap; import java.util.Scanner; import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import IPtProxy.IPtProxy; @@ -28,6 +30,7 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { private final WeakReference contextRef; private long snowflakePort = -1; private FileObserver logFileObserver; + private static final Pattern SNOWFLAKE_LOG_TIMESTAMP_PATTERN = Pattern.compile("((19|2[0-9])[0-9]{2}\\/\\d{1,2}\\/\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}) ([\\S|\\s]+)"); public ClientTransportPlugin(Context context) { this.contextRef = new WeakReference<>(context); @@ -77,7 +80,7 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { int endIndex = currentBuffer.size() - 1; Collection newMessages = currentBuffer.subList(startIndex, endIndex); for (String message : newMessages) { - Log.d("[SNOWFLAKE]", message); + logSnowflakeMessage(message); } lastBuffer.addAll(newMessages); } @@ -130,4 +133,23 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { } return null; } + + private void logSnowflakeMessage(String message) { + Matcher matcher = SNOWFLAKE_LOG_TIMESTAMP_PATTERN.matcher(message); + if (matcher.matches()) { + try { + + String strippedString = matcher.group(3).trim(); + Log.d(TAG, "log: " + message); + Log.d(TAG, "log stripped: " + strippedString); + if (strippedString.length() > 0) { + TorStatusObservable.logSnowflakeMessage(contextRef.get(), strippedString); + } + } catch (IndexOutOfBoundsException | IllegalStateException e) { + e.printStackTrace(); + } + } else { + TorStatusObservable.logSnowflakeMessage(contextRef.get(), message); + } + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index 11baecbf..64e68727 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -1,10 +1,8 @@ package se.leap.bitmaskclient.tor; import android.content.Context; -import android.os.Handler; import android.util.Log; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.util.Observable; @@ -24,10 +22,15 @@ public class TorStatusObservable extends Observable { UNKOWN } + public static final String LOG_TAG_TOR = "[TOR]"; + public static final String LOG_TAG_SNOWFLAKE = "[SNOWFLAKE]"; + private static TorStatusObservable instance; private TorStatus status = TorStatus.UNKOWN; private final TorNotificationManager torNotificationManager; private String lastError; + private String lastTorLog; + private String lastSnowflakeLog; private int port = -1; private int bootstrapPercent = -1; private Vector lastLogs = new Vector<>(100); @@ -47,16 +50,32 @@ public class TorStatusObservable extends Observable { return getInstance().status; } - public static void logMessage(Context context, String tag, String message) { - Log.d(tag, message); + public static void logSnowflakeMessage(Context context, String message) { + Log.d(LOG_TAG_SNOWFLAKE, message); addLog(message); + getInstance().lastSnowflakeLog = message; if (getInstance().status != TorStatus.OFF) { - getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), message, getInstance().bootstrapPercent); + getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), getNotificationLog(), getNotificationProgress()); } instance.setChanged(); instance.notifyObservers(); } + private static String getNotificationLog() { + String snowflakeIcon = new String(Character.toChars(0x2744)); + String snowflakeLog = getInstance().lastSnowflakeLog; + // we don't want to show the response json in the notification + if (snowflakeLog != null && snowflakeLog.contains("Received answer: {")) { + snowflakeLog = "Received answer."; + } + return "Tor: " + getInstance().lastTorLog + "\n" + + snowflakeIcon + ": " + snowflakeLog; + } + + private static int getNotificationProgress() { + return getInstance().status == TorStatus.STARTING ? getInstance().bootstrapPercent : -1; + } + private static void addLog(String message) { if (instance.lastLogs.size() > 100) { instance.lastLogs.remove(0); @@ -75,18 +94,15 @@ public class TorStatusObservable extends Observable { if (bootstrapPercent != -1) { getInstance().bootstrapPercent = bootstrapPercent; } - int progress = getInstance().status == TorStatus.STARTING ? getInstance().bootstrapPercent : -1; - if (getInstance().status == TorStatus.OFF) { getInstance().torNotificationManager.cancelNotifications(context); - } else if (logKey != null) { - String log = getStringFor(context, logKey); - addLog(log); - getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), log, progress); } else { - String log = instance.lastLogs.size() > 0 ? instance.lastLogs.lastElement() : ""; - getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), log, progress); + if (logKey != null) { + getInstance().lastTorLog = getStringFor(context, logKey); + addLog(getInstance().lastTorLog); + } + getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), getNotificationLog(), getNotificationProgress()); } instance.setChanged(); -- cgit v1.2.3 From f6b8a78812c46679cf416edc303d88e840750827 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 16 Oct 2021 13:52:24 +0200 Subject: cleanup imports --- .../main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java index 8148fd94..45570857 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java @@ -23,12 +23,9 @@ import android.app.NotificationManager; import android.content.Context; import android.os.Build; -import androidx.annotation.NonNull; import androidx.core.app.NotificationCompat; import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.base.models.Provider; -import se.leap.bitmaskclient.base.models.ProviderObservable; public class TorNotificationManager { public final static int TOR_SERVICE_NOTIFICATION_ID = 10; -- cgit v1.2.3 From b4854af31a5026dd5129d994dd9d505dc4a63d70 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 16 Oct 2021 14:15:11 +0200 Subject: remove unneeded logs --- app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java index 1d2b7cea..6228453e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java @@ -138,10 +138,7 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { Matcher matcher = SNOWFLAKE_LOG_TIMESTAMP_PATTERN.matcher(message); if (matcher.matches()) { try { - String strippedString = matcher.group(3).trim(); - Log.d(TAG, "log: " + message); - Log.d(TAG, "log stripped: " + strippedString); if (strippedString.length() > 0) { TorStatusObservable.logSnowflakeMessage(contextRef.get(), strippedString); } -- cgit v1.2.3 From 726f06f564e2743048baea5624daa96a511aace3 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 16 Oct 2021 15:31:33 +0200 Subject: tweak snowflake log message --- app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index 64e68727..449955af 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -66,7 +66,7 @@ public class TorStatusObservable extends Observable { String snowflakeLog = getInstance().lastSnowflakeLog; // we don't want to show the response json in the notification if (snowflakeLog != null && snowflakeLog.contains("Received answer: {")) { - snowflakeLog = "Received answer."; + snowflakeLog = "Received Answer."; } return "Tor: " + getInstance().lastTorLog + "\n" + snowflakeIcon + ": " + snowflakeLog; -- cgit v1.2.3 From 213e42d82d360cdf7f5632782a9a0cb879c1b4f5 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 22 Oct 2021 23:36:34 +0200 Subject: show tor and snowflake connection status in provider setup screens --- .../activities/ConfigWizardBaseActivity.java | 161 ++++++++++++++++++++- .../bitmaskclient/tor/TorStatusObservable.java | 23 ++- 2 files changed, 173 insertions(+), 11 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java index 7d452200..a0c046de 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java @@ -5,20 +5,28 @@ import android.graphics.PorterDuff; import android.graphics.Rect; import android.os.Build; import android.os.Bundle; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.widget.Button; import android.widget.LinearLayout; import android.widget.ProgressBar; +import android.widget.RelativeLayout; import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.appcompat.widget.AppCompatTextView; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.Guideline; import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import java.util.List; import java.util.Observable; import java.util.Observer; @@ -31,8 +39,14 @@ import se.leap.bitmaskclient.tor.TorStatusObservable; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.view.View.GONE; import static android.view.View.VISIBLE; +import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static se.leap.bitmaskclient.tor.TorStatusObservable.getBootstrapProgress; +import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastLogs; +import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastSnowflakeLog; +import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastTorLog; +import static se.leap.bitmaskclient.tor.TorStatusObservable.getStringForCurrentStatus; /** * Base Activity for configuration wizard activities @@ -54,6 +68,32 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple @BindView(R.id.loading_screen) protected LinearLayout loadingScreen; + @Nullable + @BindView(R.id.btn_connection_detail) + protected Button connectionDetailBtn; + + @Nullable + @BindView(R.id.connection_detail_container) + protected RelativeLayout connectionDetailContainer; + + @Nullable + @BindView(R.id.log_container) + protected RelativeLayout logsContainer; + + @Nullable + @BindView(R.id.tor_state) + protected AppCompatTextView torState; + + @Nullable + @BindView(R.id.snowflake_state) + protected AppCompatTextView snowflakeState; + + @Nullable + @BindView(R.id.connection_detail_logs) + protected RecyclerView connectionDetailLogs; + + private TorLogAdapter torLogAdapter; + @Nullable @BindView(R.id.progressbar) protected ProgressBar progressBar; @@ -157,7 +197,7 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple super.onResume(); isActivityShowing = true; TorStatusObservable.getInstance().addObserver(this); - setProgressbarDescription(TorStatusObservable.getStringForCurrentStatus(this)); + setProgressbarDescription(getStringForCurrentStatus(this)); } protected void restoreState(Bundle savedInstanceState) { @@ -178,10 +218,48 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple providerHeaderView.setTitle(providerHeaderText); } + protected void showConnectionDetails() { + if (loadingScreen == null) { + return; + } + LinearLayoutManager layoutManager = new LinearLayoutManager(this); + connectionDetailLogs.setLayoutManager(layoutManager); + connectionDetailLogs.addItemDecoration( new DividerItemDecoration(this, layoutManager.getOrientation())); + torLogAdapter = new TorLogAdapter(getLastLogs()); + connectionDetailLogs.setAdapter(torLogAdapter); + + connectionDetailLogs.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (newState != SCROLL_STATE_IDLE) { + torLogAdapter.postponeUpdate = true; + } else if (newState == SCROLL_STATE_IDLE && getFirstVisibleItemPosion() == 0) { + torLogAdapter.postponeUpdate = false; + } + } + }); + + snowflakeState.setText(getLastSnowflakeLog()); + torState.setText(getLastTorLog()); + connectionDetailBtn.setOnClickListener(v -> { + connectionDetailBtn.setVisibility(GONE); + logsContainer.setVisibility(VISIBLE); + }); + connectionDetailContainer.setVisibility(VISIBLE); + } + + private int getFirstVisibleItemPosion() { + return ((LinearLayoutManager)connectionDetailLogs.getLayoutManager()).findFirstVisibleItemPosition(); + } + protected void hideProgressBar() { if (loadingScreen == null) { return; } + connectionDetailBtn.setVisibility(VISIBLE); + connectionDetailContainer.setVisibility(GONE); + logsContainer.setVisibility(GONE); loadingScreen.setVisibility(GONE); content.setVisibility(VISIBLE); } @@ -195,19 +273,28 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple } protected void setProgressbarTitle(@StringRes int progressbarTitle) { - if (this.progressbarTitle == null) { + if (loadingScreen == null) { return; } this.progressbarTitle.setText(progressbarTitle); } protected void setProgressbarDescription(String progressbarDescription) { - if (this.progressbarDescription == null) { + if (loadingScreen == null) { return; } this.progressbarDescription.setText(progressbarDescription); } + protected void setConfigProgress(int value) { + if (loadingScreen == null) { + return; + } + + progressBar.setProgress(value, true); + progressBar.setIndeterminate(value >= 100 || value < 0); + } + protected void showCompactLayout() { if (isCompactLayout) { @@ -307,7 +394,73 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple @Override public void update(Observable o, Object arg) { if (o instanceof TorStatusObservable) { - runOnUiThread(() -> setProgressbarDescription(TorStatusObservable.getStringForCurrentStatus(ConfigWizardBaseActivity.this))); + runOnUiThread(() -> { + if (TorStatusObservable.getStatus() != TorStatusObservable.TorStatus.OFF && loadingScreen != null) { + if (connectionDetailContainer.getVisibility() == GONE) { + showConnectionDetails(); + } else { + setLogs(getLastTorLog(), getLastSnowflakeLog(), getLastLogs()); + } + } + setProgressbarDescription(getStringForCurrentStatus(ConfigWizardBaseActivity.this)); + setConfigProgress(getBootstrapProgress()); + }); + } + } + + protected void setLogs(String torLog, String snowflakeLog, List lastLogs) { + if (loadingScreen == null) { + return; + } + torLogAdapter.updateData(lastLogs); + torState.setText(torLog); + snowflakeState.setText(snowflakeLog); + } + + static class TorLogAdapter extends RecyclerView.Adapter { + private List values; + private boolean postponeUpdate; + + static class ViewHolder extends RecyclerView.ViewHolder { + public AppCompatTextView logTextLabel; + public View layout; + + public ViewHolder(View v) { + super(v); + layout = v; + logTextLabel = v.findViewById(android.R.id.text1); + } + } + + public void updateData(List data) { + values = data; + if (!postponeUpdate) { + notifyDataSetChanged(); + } + } + + public TorLogAdapter(List data) { + values = data; + } + + @NonNull + @Override + public TorLogAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from( + parent.getContext()); + View v = inflater.inflate(R.layout.v_log_item, parent, false); + return new TorLogAdapter.ViewHolder(v); + } + + @Override + public void onBindViewHolder(TorLogAdapter.ViewHolder holder, final int position) { + final String log = values.get(position); + holder.logTextLabel.setText(log); + } + + @Override + public int getItemCount() { + return values.size(); } } } diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index 449955af..281b21c0 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -55,7 +55,7 @@ public class TorStatusObservable extends Observable { addLog(message); getInstance().lastSnowflakeLog = message; if (getInstance().status != TorStatus.OFF) { - getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), getNotificationLog(), getNotificationProgress()); + getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), getNotificationLog(), getBootstrapProgress()); } instance.setChanged(); instance.notifyObservers(); @@ -72,15 +72,15 @@ public class TorStatusObservable extends Observable { snowflakeIcon + ": " + snowflakeLog; } - private static int getNotificationProgress() { + public static int getBootstrapProgress() { return getInstance().status == TorStatus.STARTING ? getInstance().bootstrapPercent : -1; } private static void addLog(String message) { if (instance.lastLogs.size() > 100) { - instance.lastLogs.remove(0); + instance.lastLogs.remove(99); } - instance.lastLogs.add(message); + instance.lastLogs.add(0, message.trim()); } public static void updateState(Context context, String status) { @@ -102,7 +102,7 @@ public class TorStatusObservable extends Observable { getInstance().lastTorLog = getStringFor(context, logKey); addLog(getInstance().lastTorLog); } - getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), getNotificationLog(), getNotificationProgress()); + getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), getNotificationLog(), getBootstrapProgress()); } instance.setChanged(); @@ -168,8 +168,17 @@ public class TorStatusObservable extends Observable { @Nullable - public String getLastError() { - return lastError; + public static String getLastTorLog() { + return getInstance().lastTorLog; + } + + @Nullable + public static String getLastSnowflakeLog() { + return getInstance().lastSnowflakeLog; + } + + public static Vector getLastLogs() { + return getInstance().lastLogs; } public static String getStringForCurrentStatus(Context context) { -- cgit v1.2.3 From 1640f7bbfa53b84ebf539f027d5cc3c9ba441401 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 22 Oct 2021 23:45:57 +0200 Subject: fix utf-8 string icon variable naming --- .../java/se/leap/bitmaskclient/eip/VpnNotificationManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java index 6fac0f72..667b8892 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java @@ -131,7 +131,7 @@ public class VpnNotificationManager { String notificationChannelNewstatusId, VpnServiceCallback vpnServiceCallback) { String cancelString; CharSequence bigmessage = null; - String ghostIcon = new String(Character.toChars(0x1f309)); + String bridgeIcon = new String(Character.toChars(0x1f309)); switch (status) { // show cancel if no connection @@ -143,7 +143,7 @@ public class VpnNotificationManager { if (isObfuscated && Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { Spannable spannable = new SpannableString(context.getString(R.string.obfuscated_connection_try)); spannable.setSpan(new StyleSpan(Typeface.ITALIC), 0, spannable.length() -1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - bigmessage = TextUtils.concat(spannable, " " + ghostIcon + "\n" + msg); + bigmessage = TextUtils.concat(spannable, " " + bridgeIcon + "\n" + msg); } break; @@ -152,14 +152,14 @@ public class VpnNotificationManager { if (isObfuscated && Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { Spannable spannable = new SpannableString(context.getString(R.string.obfuscated_connection)); spannable.setSpan(new StyleSpan(Typeface.ITALIC), 0, spannable.length() -1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - bigmessage = TextUtils.concat(spannable, " " + ghostIcon + "\n" + msg); + bigmessage = TextUtils.concat(spannable, " " + bridgeIcon + "\n" + msg); } default: cancelString = context.getString(R.string.cancel_connection); } if (isObfuscated) { - msg = ghostIcon + " " + msg; + msg = bridgeIcon + " " + msg; } NotificationCompat.Action.Builder actionBuilder = new NotificationCompat.Action. -- cgit v1.2.3 From 62d2bdacec6c54f4453f1ad20425e99254998e9a Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 23 Oct 2021 00:59:46 +0200 Subject: rename usePluggableTransports prefrence to useBridges, start snowflake if useBridges is true --- .../se/leap/bitmaskclient/base/MainActivity.java | 2 +- .../base/fragments/GatewaySelectionFragment.java | 4 ++-- .../base/fragments/MainActivityErrorDialog.java | 11 +++++------ .../base/fragments/NavigationDrawerFragment.java | 12 ++++++------ .../se/leap/bitmaskclient/base/models/Constants.java | 2 +- .../bitmaskclient/base/utils/PreferenceHelper.java | 20 ++++++++++++-------- app/src/main/java/se/leap/bitmaskclient/eip/EIP.java | 6 +++--- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 5 ++--- .../bitmaskclient/providersetup/ProviderAPI.java | 2 +- .../providersetup/ProviderApiManagerBase.java | 2 +- 10 files changed, 34 insertions(+), 32 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java index 99f6826f..18ac8b7c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java @@ -195,7 +195,7 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, storeProviderInPreferences(preferences, provider); ProviderObservable.getInstance().updateProvider(provider); if (!provider.supportsPluggableTransports()) { - PreferenceHelper.usePluggableTransports(this, false); + PreferenceHelper.useBridges(this, false); } navigationDrawerFragment.refresh(); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index 84024962..d1222cd7 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -56,7 +56,7 @@ import static android.view.View.VISIBLE; import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; import static se.leap.bitmaskclient.base.models.Constants.PREFERRED_CITY; import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; -import static se.leap.bitmaskclient.base.models.Constants.USE_PLUGGABLE_TRANSPORTS; +import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setPreferredCity; @@ -162,7 +162,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (USE_PLUGGABLE_TRANSPORTS.equals(key)) { + if (USE_BRIDGES.equals(key)) { locationListAdapter.updateData(gatewaysManager.getGatewayLocations()); setVpnButtonState(); } else if (PREFERRED_CITY.equals(key)) { diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java index 4034bd04..86f8471c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java @@ -18,7 +18,6 @@ package se.leap.bitmaskclient.base.fragments; import android.app.Dialog; import android.content.Context; -import android.content.DialogInterface; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -42,8 +41,8 @@ import static se.leap.bitmaskclient.eip.EIP.EIPErrors.UNKNOWN; import static se.leap.bitmaskclient.eip.EIP.EIPErrors.valueOf; import static se.leap.bitmaskclient.eip.EIP.ERRORS; import static se.leap.bitmaskclient.eip.EIP.ERRORID; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePluggableTransports; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.usePluggableTransports; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges; /** * Implements an error dialog for the main activity. @@ -129,14 +128,14 @@ public class MainActivityErrorDialog extends DialogFragment { EipCommand.startVPN(applicationContext, false); }); } else if (provider.supportsPluggableTransports()) { - if (getUsePluggableTransports(applicationContext)) { + if (getUseBridges(applicationContext)) { builder.setPositiveButton(warning_option_try_ovpn, ((dialog, which) -> { - usePluggableTransports(applicationContext, false); + useBridges(applicationContext, false); EipCommand.startVPN(applicationContext, false); })); } else { builder.setPositiveButton(warning_option_try_pt, ((dialog, which) -> { - usePluggableTransports(applicationContext, true); + useBridges(applicationContext, true); EipCommand.startVPN(applicationContext, false); })); } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java index f905a7d2..a13692a5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java @@ -76,7 +76,7 @@ import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER; import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL; -import static se.leap.bitmaskclient.base.models.Constants.USE_PLUGGABLE_TRANSPORTS; +import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES; import static se.leap.bitmaskclient.R.string.about_fragment_title; import static se.leap.bitmaskclient.R.string.exclude_apps_fragment_title; import static se.leap.bitmaskclient.R.string.log_fragment_title; @@ -84,10 +84,10 @@ import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getSaveBattery; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getShowAlwaysOnDialog; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePluggableTransports; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.saveBattery; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.showExperimentalFeatures; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.usePluggableTransports; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges; /** * Fragment used for managing interactions for and presentation of a navigation drawer. @@ -300,12 +300,12 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen IconSwitchEntry useBridges = drawerView.findViewById(R.id.bridges_switch); if (ProviderObservable.getInstance().getCurrentProvider().supportsPluggableTransports()) { useBridges.setVisibility(VISIBLE); - useBridges.setChecked(getUsePluggableTransports(getContext())); + useBridges.setChecked(getUseBridges(getContext())); useBridges.setOnCheckedChangeListener((buttonView, isChecked) -> { if (!buttonView.isPressed()) { return; } - usePluggableTransports(getContext(), isChecked); + useBridges(getContext(), isChecked); if (VpnStatus.isVPNActive()) { EipCommand.startVPN(getContext(), false); closeDrawer(); @@ -675,7 +675,7 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (key.equals(USE_PLUGGABLE_TRANSPORTS)) { + if (key.equals(USE_BRIDGES)) { initUseBridgesEntry(); } else if (key.equals(USE_IPv6_FIREWALL)) { initFirewallEntry(); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java index f627a24e..d91880c6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java @@ -32,7 +32,7 @@ public interface Constants { String CLEARLOG = "clearlogconnect"; String LAST_USED_PROFILE = "last_used_profile"; String EXCLUDED_APPS = "excluded_apps"; - String USE_PLUGGABLE_TRANSPORTS = "usePluggableTransports"; + String USE_BRIDGES = "usePluggableTransports"; String ALLOW_TETHERING_BLUETOOTH = "tethering_bluetooth"; String ALLOW_TETHERING_WIFI = "tethering_wifi"; String ALLOW_TETHERING_USB = "tethering_usb"; diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java index cbea2815..28242388 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java @@ -33,8 +33,7 @@ import static se.leap.bitmaskclient.base.models.Constants.RESTART_ON_UPDATE; import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.base.models.Constants.SHOW_EXPERIMENTAL; import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL; -import static se.leap.bitmaskclient.base.models.Constants.USE_PLUGGABLE_TRANSPORTS; -import static se.leap.bitmaskclient.base.models.Constants.USE_TOR; +import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES; /** * Created by cyberta on 18.03.18. @@ -141,12 +140,17 @@ public class PreferenceHelper { return getBoolean(context, RESTART_ON_UPDATE, false); } - public static boolean getUsePluggableTransports(Context context) { - return getBoolean(context, USE_PLUGGABLE_TRANSPORTS, false); + + public static boolean getUseBridges(SharedPreferences preferences) { + return preferences.getBoolean(USE_BRIDGES, false); + } + + public static boolean getUseBridges(Context context) { + return getBoolean(context, USE_BRIDGES, false); } - public static void usePluggableTransports(Context context, boolean isEnabled) { - putBoolean(context, USE_PLUGGABLE_TRANSPORTS, isEnabled); + public static void useBridges(Context context, boolean isEnabled) { + putBoolean(context, USE_BRIDGES, isEnabled); } public static void saveBattery(Context context, boolean isEnabled) { @@ -213,7 +217,7 @@ public class PreferenceHelper { putString(context, PREFERRED_CITY, city); } - public static Boolean useTor(SharedPreferences preferences) { + /* public static Boolean useTor(SharedPreferences preferences) { return preferences.getBoolean(USE_TOR, true); } @@ -223,7 +227,7 @@ public class PreferenceHelper { public static void setUseTor(Context context, boolean useTor) { putBoolean(context, USE_TOR, useTor); - } + }*/ public static JSONObject getEipDefinitionFromPreferences(SharedPreferences preferences) { JSONObject result = new JSONObject(); diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java index 6919a532..dd9054f1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -85,7 +85,7 @@ import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICA import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePluggableTransports; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_PROFILE; import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_VPN_PREPARE; @@ -315,7 +315,7 @@ public final class EIP extends JobIntentService implements Observer { */ private void launchActiveGateway(Gateway gateway, int nClosestGateway, Bundle result) { VpnProfile profile; - Connection.TransportType transportType = getUsePluggableTransports(this) ? OBFS4 : OPENVPN; + Connection.TransportType transportType = getUseBridges(this) ? OBFS4 : OPENVPN; if (gateway == null || (profile = gateway.getProfile(transportType)) == null) { String preferredLocation = getPreferredCity(getApplicationContext()); @@ -537,7 +537,7 @@ public final class EIP extends JobIntentService implements Observer { if (isManualGatewaySelection) { return R.string.warning_no_more_gateways_manual_gw_selection; } else if (ProviderObservable.getInstance().getCurrentProvider().supportsPluggableTransports()) { - if (PreferenceHelper.getUsePluggableTransports(getApplicationContext())) { + if (PreferenceHelper.getUseBridges(getApplicationContext())) { return R.string.warning_no_more_gateways_use_ovpn; } else { return R.string.warning_no_more_gateways_use_pt; diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 77ecfc5f..05775d13 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -32,7 +32,6 @@ import java.io.IOException; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -53,7 +52,7 @@ import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE; import static se.leap.bitmaskclient.base.models.Constants.SORTED_GATEWAYS; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePluggableTransports; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; /** * @author parmegv @@ -82,7 +81,7 @@ public class GatewaysManager { } public Gateway select(int nClosest, String city) { - Connection.TransportType transportType = getUsePluggableTransports(context) ? OBFS4 : OPENVPN; + Connection.TransportType transportType = getUseBridges(context) ? OBFS4 : OPENVPN; if (presortedList.size() > 0) { return getGatewayFromPresortedList(nClosest, transportType, city); } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index e818f587..ceb2f2b4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -197,7 +197,7 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB * @throws IllegalStateException thrown if this method was not called from a background thread */ private void initTorServiceConnection(Context context) { - if (PreferenceHelper.useTor(context)) { + if (PreferenceHelper.getUseBridges(context)) { try { if (torServiceConnection == null) { Log.d(TAG, "serviceConnection is still null"); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 780ecaed..6e07e84b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -296,7 +296,7 @@ public abstract class ProviderApiManagerBase { } protected boolean startTorProxy() throws InterruptedException, TimeoutException { - if (PreferenceHelper.useTor(preferences) && + if (PreferenceHelper.getUseBridges(preferences) && EipStatus.getInstance().isDisconnected() && serviceCallback.isConnectedToWifi() ) { -- cgit v1.2.3 From 01e40b1a843326036425727355550dba8bd66335 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 24 Oct 2021 16:47:12 +0200 Subject: cancel tor and provider setup on pressing back button --- .../se/leap/bitmaskclient/eip/EipSetupObserver.java | 3 +-- .../providersetup/ProviderApiManagerBase.java | 16 ++++++++++------ .../activities/ProviderSetupBaseActivity.java | 4 ++-- .../se/leap/bitmaskclient/tor/TorStatusObservable.java | 18 ++++++++++++++++++ 4 files changed, 31 insertions(+), 10 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java index 23fbdc0c..203885a1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java @@ -368,8 +368,7 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta observedProfileFromVpnStatus = null; this.changingGateway.set(changingGateway); if (TorStatusObservable.getStatus() != OFF) { - Intent intent = new Intent(context, TorService.class); - context.stopService(intent); + TorStatusObservable.shutdownTor(context); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 6e07e84b..bc173b36 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -192,11 +192,12 @@ public abstract class ProviderApiManagerBase { } // uncomment for testing --v - /* try { + try { startTorProxy(); } catch (InterruptedException | TimeoutException e) { e.printStackTrace(); - } */ + return; + } Bundle result = new Bundle(); switch (action) { @@ -302,6 +303,9 @@ public abstract class ProviderApiManagerBase { ) { serviceCallback.startTorService(); waitForTorCircuits(); + if (TorStatusObservable.isCancelled()) { + throw new InterruptedException("cancelled Tor setup"); + } int port = serviceCallback.getTorHttpTunnelPort(); TorStatusObservable.setProxyPort(port); return port != -1; @@ -314,17 +318,17 @@ public abstract class ProviderApiManagerBase { return; } CountDownLatch countDownLatch = new CountDownLatch(1); - AtomicBoolean successfulSetup = new AtomicBoolean(false); + AtomicBoolean stopWaiting = new AtomicBoolean(false); Observer observer = (o, arg) -> { - if (TorStatusObservable.getStatus() == ON) { - successfulSetup.set(true); + if (TorStatusObservable.getStatus() == ON || TorStatusObservable.isCancelled()) { + stopWaiting.set(true); countDownLatch.countDown(); } }; TorStatusObservable.getInstance().addObserver(observer); countDownLatch.await(180, TimeUnit.SECONDS); TorStatusObservable.getInstance().deleteObserver(observer); - if (!successfulSetup.get()) { + if (!stopWaiting.get()) { throw new TimeoutException("Timeout reached"); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java index e4569c51..6395c7ae 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java @@ -170,8 +170,8 @@ public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity public void cancelSettingUpProvider(boolean stopTor) { if (stopTor && TorStatusObservable.getStatus() != OFF) { - Intent torServiceIntent = new Intent(getApplicationContext(), TorService.class); - stopService(torServiceIntent); + Log.d(TAG, "SHUTDOWN - cancelSettingUpProvider stopTor:" + stopTor); + TorStatusObservable.shutdownTor(this); } providerConfigState = PROVIDER_NOT_SET; provider = null; diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index 281b21c0..fb7e4d93 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -1,10 +1,13 @@ package se.leap.bitmaskclient.tor; import android.content.Context; +import android.content.Intent; import android.util.Log; import androidx.annotation.Nullable; +import org.torproject.jni.TorService; + import java.util.Observable; import java.util.Vector; @@ -22,6 +25,8 @@ public class TorStatusObservable extends Observable { UNKOWN } + private boolean cancelled = false; + public static final String LOG_TAG_TOR = "[TOR]"; public static final String LOG_TAG_SNOWFLAKE = "[SNOWFLAKE]"; @@ -97,6 +102,7 @@ public class TorStatusObservable extends Observable { if (getInstance().status == TorStatus.OFF) { getInstance().torNotificationManager.cancelNotifications(context); + getInstance().cancelled = false; } else { if (logKey != null) { getInstance().lastTorLog = getStringFor(context, logKey); @@ -195,4 +201,16 @@ public class TorStatusObservable extends Observable { } return null; } + + public static void shutdownTor(Context context) { + getInstance().cancelled = true; + getInstance().notifyObservers(); + + Intent intent = new Intent(context, TorService.class); + boolean stopped = context.stopService(intent); + } + + public static boolean isCancelled() { + return getInstance().cancelled; + } } -- cgit v1.2.3 From 679d10626457306000b1148f8e94a16f6a074f96 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 24 Oct 2021 16:48:49 +0200 Subject: remove unused service action STOP_PROXY --- app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java | 1 - .../se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index ceb2f2b4..c8cc786a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -67,7 +67,6 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB final public static String TAG = ProviderAPI.class.getSimpleName(), - STOP_PROXY = "stopProxy", SET_UP_PROVIDER = "setUpProvider", UPDATE_PROVIDER_DETAILS = "updateProviderDetails", DOWNLOAD_GEOIP_JSON = "downloadGeoIpJson", diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index bc173b36..d646b4bb 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -127,7 +127,6 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_OK; import static se.leap.bitmaskclient.providersetup.ProviderAPI.RECEIVER_KEY; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SET_UP_PROVIDER; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SIGN_UP; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.STOP_PROXY; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_LOGIN; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_LOGOUT; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_SIGNUP; @@ -185,7 +184,7 @@ public abstract class ProviderApiManagerBase { Provider provider = null; if (command.getParcelableExtra(PROVIDER_KEY) != null) { provider = command.getParcelableExtra(PROVIDER_KEY); - } else if (!STOP_PROXY.equals(action)) { + } else { //TODO: consider returning error back e.g. NO_PROVIDER Log.e(TAG, action +" called without provider!"); return; -- cgit v1.2.3 From d5584eff59052d08ddcafd84c7b733720c038512 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 4 Nov 2021 14:53:36 +0100 Subject: use deprecated method to initiate FileObserver for now to avoid crashes on old devices --- app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java index 6228453e..5fc604e5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java @@ -66,7 +66,7 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { private void watchLogFile(File logfile) { final Vector lastBuffer = new Vector<>(); - logFileObserver = new FileObserver(logfile) { + logFileObserver = new FileObserver(logfile.getAbsolutePath()) { @Override public void onEvent(int event, @Nullable String name) { if (FileObserver.MODIFY == event) { -- cgit v1.2.3 From d27af3b17d6636de8b2755090b6fe6329531f639 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 4 Nov 2021 16:45:54 +0100 Subject: remove unused UNKNOWN TorStatus state --- app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index fb7e4d93..f4f0ff11 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -22,7 +22,7 @@ public class TorStatusObservable extends Observable { OFF, STARTING, STOPPING, - UNKOWN + // UNKOWN } private boolean cancelled = false; @@ -31,7 +31,7 @@ public class TorStatusObservable extends Observable { public static final String LOG_TAG_SNOWFLAKE = "[SNOWFLAKE]"; private static TorStatusObservable instance; - private TorStatus status = TorStatus.UNKOWN; + private TorStatus status = TorStatus.OFF; private final TorNotificationManager torNotificationManager; private String lastError; private String lastTorLog; @@ -196,7 +196,6 @@ public class TorStatusObservable extends Observable { case STOPPING: return context.getString(R.string.tor_stopping); case OFF: - case UNKOWN: break; } return null; -- cgit v1.2.3 From 88b7dc2eb3dcbec8d1e637096867c15211818677 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 5 Nov 2021 02:38:26 +0100 Subject: Ensure tor state is set to OFF after snowflake completely stopped. --- .../bitmaskclient/providersetup/ProviderAPI.java | 34 ++++++------ .../providersetup/ProviderApiManagerBase.java | 32 ++++------- .../bitmaskclient/tor/ClientTransportPlugin.java | 11 ++++ .../bitmaskclient/tor/TorStatusObservable.java | 63 ++++++++++++++++++++-- 4 files changed, 96 insertions(+), 44 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index c8cc786a..4afeb26e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -154,7 +154,7 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB } @Override - public void startTorService() { + public void startTorService() throws InterruptedException, IllegalStateException { initTorServiceConnection(this); Intent torServiceIntent = new Intent(this, TorService.class); @@ -171,12 +171,16 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB @Override public int getTorHttpTunnelPort() { - initTorServiceConnection(this); - if (torServiceConnection != null) { - int tunnelPort = torServiceConnection.torService.getHttpTunnelPort(); - torServiceConnection.close(); - torServiceConnection = null; - return tunnelPort; + try { + initTorServiceConnection(this); + if (torServiceConnection != null) { + int tunnelPort = torServiceConnection.torService.getHttpTunnelPort(); + torServiceConnection.close(); + torServiceConnection = null; + return tunnelPort; + } + } catch (InterruptedException | IllegalStateException e) { + e.printStackTrace(); } return -1; @@ -195,18 +199,14 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB * @throws InterruptedException thrown if thread gets interrupted * @throws IllegalStateException thrown if this method was not called from a background thread */ - private void initTorServiceConnection(Context context) { + private void initTorServiceConnection(Context context) throws InterruptedException, IllegalStateException { if (PreferenceHelper.getUseBridges(context)) { - try { - if (torServiceConnection == null) { - Log.d(TAG, "serviceConnection is still null"); - if (!TorService.hasClientTransportPlugin()) { - TorService.setClientTransportPlugin(new ClientTransportPlugin(context.getApplicationContext())); - } - torServiceConnection = new TorServiceConnection(context); + if (torServiceConnection == null) { + Log.d(TAG, "serviceConnection is still null"); + if (!TorService.hasClientTransportPlugin()) { + TorService.setClientTransportPlugin(new ClientTransportPlugin(context.getApplicationContext())); } - } catch (InterruptedException | IllegalStateException e) { - e.printStackTrace(); + torServiceConnection = new TorServiceConnection(context); } } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index d646b4bb..074cc121 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -48,11 +48,7 @@ import java.security.interfaces.RSAPrivateKey; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; -import java.util.Observer; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLPeerUnverifiedException; @@ -150,7 +146,7 @@ public abstract class ProviderApiManagerBase { public interface ProviderApiServiceCallback { void broadcastEvent(Intent intent); - void startTorService(); + void startTorService() throws InterruptedException, IllegalStateException; int getTorHttpTunnelPort(); boolean isConnectedToWifi(); } @@ -190,10 +186,9 @@ public abstract class ProviderApiManagerBase { return; } - // uncomment for testing --v try { startTorProxy(); - } catch (InterruptedException | TimeoutException e) { + } catch (InterruptedException | IllegalStateException | TimeoutException e) { e.printStackTrace(); return; } @@ -295,7 +290,7 @@ public abstract class ProviderApiManagerBase { } } - protected boolean startTorProxy() throws InterruptedException, TimeoutException { + protected boolean startTorProxy() throws InterruptedException, IllegalStateException, TimeoutException { if (PreferenceHelper.getUseBridges(preferences) && EipStatus.getInstance().isDisconnected() && serviceCallback.isConnectedToWifi() @@ -303,7 +298,7 @@ public abstract class ProviderApiManagerBase { serviceCallback.startTorService(); waitForTorCircuits(); if (TorStatusObservable.isCancelled()) { - throw new InterruptedException("cancelled Tor setup"); + throw new InterruptedException("Cancelled Tor setup."); } int port = serviceCallback.getTorHttpTunnelPort(); TorStatusObservable.setProxyPort(port); @@ -316,20 +311,11 @@ public abstract class ProviderApiManagerBase { if (TorStatusObservable.getStatus() == ON) { return; } - CountDownLatch countDownLatch = new CountDownLatch(1); - AtomicBoolean stopWaiting = new AtomicBoolean(false); - Observer observer = (o, arg) -> { - if (TorStatusObservable.getStatus() == ON || TorStatusObservable.isCancelled()) { - stopWaiting.set(true); - countDownLatch.countDown(); - } - }; - TorStatusObservable.getInstance().addObserver(observer); - countDownLatch.await(180, TimeUnit.SECONDS); - TorStatusObservable.getInstance().deleteObserver(observer); - if (!stopWaiting.get()) { - throw new TimeoutException("Timeout reached"); - } + TorStatusObservable.waitUntil(this::isTorOnOrCancelled, 180); + } + + private boolean isTorOnOrCancelled() { + return TorStatusObservable.getStatus() == ON || TorStatusObservable.isCancelled(); } void resetProviderDetails(Provider provider) { diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java index 5fc604e5..5707cde0 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java @@ -4,6 +4,7 @@ import android.content.Context; import android.os.FileObserver; import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.torproject.jni.ClientTransportPluginInterface; @@ -18,6 +19,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Scanner; import java.util.Vector; +import java.util.concurrent.TimeoutException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -96,10 +98,19 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { @Override public void stop() { IPtProxy.stopSnowflake(); + try { + TorStatusObservable.waitUntil(this::isSnowflakeOff, 10); + } catch (InterruptedException | TimeoutException e) { + e.printStackTrace(); + } snowflakePort = -1; logFileObserver.stopWatching(); } + private boolean isSnowflakeOff() { + return TorStatusObservable.getSnowflakeStatus() == TorStatusObservable.SnowflakeStatus.OFF; + } + @Override public String getTorrc() { return "UseBridges 1\n" + diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index f4f0ff11..eca0f555 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -9,7 +9,12 @@ import androidx.annotation.Nullable; import org.torproject.jni.TorService; import java.util.Observable; +import java.util.Observer; import java.util.Vector; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; import se.leap.bitmaskclient.R; @@ -17,21 +22,34 @@ public class TorStatusObservable extends Observable { private static final String TAG = TorStatusObservable.class.getSimpleName(); + public interface StatusCondition { + boolean met(); + } + public enum TorStatus { ON, OFF, STARTING, - STOPPING, - // UNKOWN + STOPPING + } + + public enum SnowflakeStatus { + ON, + OFF } + // indicates if the user has cancelled Tor, the actual TorStatus can still be different until + // the TorService has sent the shutdown signal private boolean cancelled = false; public static final String LOG_TAG_TOR = "[TOR]"; public static final String LOG_TAG_SNOWFLAKE = "[SNOWFLAKE]"; + public static final String SNOWFLAKE_STARTED = "--- Starting Snowflake Client ---"; + public static final String SNOWFLAKE_STOPPED = "---- SnowflakeConn: end collecting snowflakes ---"; private static TorStatusObservable instance; private TorStatus status = TorStatus.OFF; + private SnowflakeStatus snowflakeStatus = SnowflakeStatus.OFF; private final TorNotificationManager torNotificationManager; private String lastError; private String lastTorLog; @@ -55,13 +73,50 @@ public class TorStatusObservable extends Observable { return getInstance().status; } + public static SnowflakeStatus getSnowflakeStatus() { + return getInstance().snowflakeStatus; + } + + /** + * Waits on the current Thread until a certain tor/snowflake status has been reached + * @param condition defines when wait should be interrupted + * @param timeout Timout in seconds + * @throws InterruptedException if thread was interrupted while waiting + * @throws TimeoutException thrown if timeout was reached + */ + public static void waitUntil(StatusCondition condition, int timeout) throws InterruptedException, TimeoutException { + CountDownLatch countDownLatch = new CountDownLatch(1); + final AtomicBoolean conditionMet = new AtomicBoolean(false); + Observer observer = (o, arg) -> { + if (condition.met()) { + countDownLatch.countDown(); + conditionMet.set(true); + } + }; + if (condition.met()) { + // no need to wait + return; + } + getInstance().addObserver(observer); + countDownLatch.await(timeout, TimeUnit.SECONDS); + getInstance().deleteObserver(observer); + if (!conditionMet.get()) { + throw new TimeoutException("Status condition not met within " + timeout + "s."); + } + } + public static void logSnowflakeMessage(Context context, String message) { - Log.d(LOG_TAG_SNOWFLAKE, message); addLog(message); getInstance().lastSnowflakeLog = message; if (getInstance().status != TorStatus.OFF) { getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), getNotificationLog(), getBootstrapProgress()); } + //TODO: implement proper state signalling in IPtProxy + if (SNOWFLAKE_STARTED.equals(message)) { + getInstance().snowflakeStatus = SnowflakeStatus.ON; + } else if (SNOWFLAKE_STOPPED.equals(message)) { + getInstance().snowflakeStatus = SnowflakeStatus.OFF; + } instance.setChanged(); instance.notifyObservers(); } @@ -206,7 +261,7 @@ public class TorStatusObservable extends Observable { getInstance().notifyObservers(); Intent intent = new Intent(context, TorService.class); - boolean stopped = context.stopService(intent); + context.stopService(intent); } public static boolean isCancelled() { -- cgit v1.2.3 From 7b9cb67eb7aa3eadf99a5187d2ea79b83ab57380 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 5 Nov 2021 22:53:07 +0100 Subject: localize notification channel description for tor notifications --- .../java/se/leap/bitmaskclient/tor/TorNotificationManager.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java index 45570857..c8bc0e2d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java @@ -75,15 +75,16 @@ public class TorNotificationManager { return null; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - createNotificationChannel(notificationManager); + createNotificationChannel(context, notificationManager); } return notificationManager; } @TargetApi(26) - private static void createNotificationChannel(NotificationManager notificationManager) { - CharSequence name = "Bitmask Tor Service"; - String description = "Informs about usage of bridges to configure Bitmask."; + private static void createNotificationChannel(Context context, NotificationManager notificationManager) { + String appName = context.getString(R.string.app_name); + CharSequence name = context.getString(R.string.channel_name_tor_service, appName); + String description = context.getString(R.string.channel_description_tor_service, appName); NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_NEWSTATUS_ID, name, NotificationManager.IMPORTANCE_LOW); -- cgit v1.2.3 From f317ef54d24d987698f7fe26eaccc53b0a51fe12 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 5 Nov 2021 22:55:37 +0100 Subject: tweak notification settings --- .../main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java index c8bc0e2d..507de4ae 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java @@ -61,6 +61,7 @@ public class TorNotificationManager { bigText(message)) .setTicker(message) .setContentTitle(state) + .setOnlyAlertOnce(true) .setContentText(message); if (progress > 0) { notificationBuilder.setProgress(100, progress, false); @@ -97,7 +98,8 @@ public class TorNotificationManager { NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_NEWSTATUS_ID); notificationBuilder. setDefaults(Notification.DEFAULT_ALL). - setAutoCancel(true); + setLocalOnly(true). + setAutoCancel(false); return notificationBuilder; } -- cgit v1.2.3 From a995b8a674ef8e89e0c86b0f113016f8fa07c716 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 5 Nov 2021 23:28:48 +0100 Subject: reset tor proxy port used by okhttp on bridges settings disabled --- .../main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java index 28242388..663e339e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java @@ -14,6 +14,7 @@ import java.util.Set; import de.blinkt.openvpn.VpnProfile; import se.leap.bitmaskclient.base.models.Provider; +import se.leap.bitmaskclient.tor.TorStatusObservable; import static android.content.Context.MODE_PRIVATE; import static se.leap.bitmaskclient.base.models.Constants.ALLOW_TETHERING_BLUETOOTH; @@ -151,6 +152,9 @@ public class PreferenceHelper { public static void useBridges(Context context, boolean isEnabled) { putBoolean(context, USE_BRIDGES, isEnabled); + if (!isEnabled) { + TorStatusObservable.setProxyPort(-1); + } } public static void saveBattery(Context context, boolean isEnabled) { -- cgit v1.2.3 From aecd8ca5ecf984b581e0b0165cd168976dc6c0f2 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 6 Nov 2021 00:21:05 +0100 Subject: implement tiomeout error handling + UI if tor doesn't start within 3 minutes --- .../bitmaskclient/providersetup/ProviderAPI.java | 14 +++++- .../providersetup/ProviderApiManagerBase.java | 29 ++++++++---- .../ProviderApiSetupBroadcastReceiver.java | 3 +- .../providersetup/ProviderSetupFailedDialog.java | 53 +++++++++++++++++++--- .../providersetup/ProviderSetupInterface.java | 2 +- .../activities/ProviderSetupBaseActivity.java | 2 +- 6 files changed, 83 insertions(+), 20 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index 4afeb26e..65810861 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -79,6 +79,7 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB RECEIVER_KEY = "receiver", ERRORS = "errors", ERRORID = "errorId", + INITIAL_ACTION = "initalAction", BACKEND_ERROR_KEY = "error", BACKEND_ERROR_MESSAGE = "message", USER_MESSAGE = "userMessage", @@ -100,7 +101,8 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE = 15, INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE = 16, CORRECTLY_DOWNLOADED_GEOIP_JSON = 17, - INCORRECTLY_DOWNLOADED_GEOIP_JSON = 18; + INCORRECTLY_DOWNLOADED_GEOIP_JSON = 18, + TOR_TIMEOUT = 19; ProviderApiManager providerApiManager; private volatile TorServiceConnection torServiceConnection; @@ -137,6 +139,10 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB @Override public void onDestroy() { super.onDestroy(); + closeTorServiceConnection(); + } + + private void closeTorServiceConnection() { if (torServiceConnection != null) { torServiceConnection.close(); torServiceConnection = null; @@ -168,6 +174,12 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB } } + @Override + public void stopTorService() throws IllegalStateException { + closeTorServiceConnection(); + Intent stopIntent = new Intent(this, TorService.class); + stopService(stopIntent); + } @Override public int getTorHttpTunnelPort() { diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 074cc121..555eb21d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -114,6 +114,7 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLO import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON; import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.INITIAL_ACTION; import static se.leap.bitmaskclient.providersetup.ProviderAPI.LOGOUT_FAILED; import static se.leap.bitmaskclient.providersetup.ProviderAPI.LOG_IN; import static se.leap.bitmaskclient.providersetup.ProviderAPI.LOG_OUT; @@ -126,12 +127,14 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.SIGN_UP; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_LOGIN; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_LOGOUT; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_SIGNUP; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.TOR_TIMEOUT; import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_PROVIDER_DETAILS; import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE; import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING; import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON; import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_INVALID_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_TOR_TIMEOUT; import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.ON; import static se.leap.bitmaskclient.tor.TorStatusObservable.getProxyPort; @@ -147,6 +150,7 @@ public abstract class ProviderApiManagerBase { public interface ProviderApiServiceCallback { void broadcastEvent(Intent intent); void startTorService() throws InterruptedException, IllegalStateException; + void stopTorService() throws IllegalStateException; int getTorHttpTunnelPort(); boolean isConnectedToWifi(); } @@ -188,10 +192,16 @@ public abstract class ProviderApiManagerBase { try { startTorProxy(); - } catch (InterruptedException | IllegalStateException | TimeoutException e) { + } catch (InterruptedException | IllegalStateException e) { e.printStackTrace(); return; - } + } catch (TimeoutException e) { + serviceCallback.stopTorService(); + Bundle result = new Bundle(); + setErrorResult(result, action, R.string.error_tor_timeout, ERROR_TOR_TIMEOUT.toString()); + sendToReceiverOrBroadcast(receiver, TOR_TIMEOUT, result, provider); + return; + } Bundle result = new Bundle(); switch (action) { @@ -348,10 +358,11 @@ public abstract class ProviderApiManagerBase { } } - private void addErrorMessageToJson(JSONObject jsonObject, String errorMessage, String errorId) { + private void addErrorMessageToJson(JSONObject jsonObject, String initialAction, String errorMessage, String errorId) { try { jsonObject.put(ERRORS, errorMessage); - jsonObject.put(ERRORID, errorId); + jsonObject.putOpt(ERRORID, errorId); + jsonObject.putOpt(INITIAL_ACTION, initialAction); } catch (JSONException e) { e.printStackTrace(); } @@ -908,13 +919,13 @@ public abstract class ProviderApiManagerBase { } Bundle setErrorResult(Bundle result, int errorMessageId, String errorId) { + return setErrorResult(result, null, errorMessageId, errorId); + } + + Bundle setErrorResult(Bundle result, String initialAction, int errorMessageId, String errorId) { JSONObject errorJson = new JSONObject(); String errorMessage = getProviderFormattedString(resources, errorMessageId); - if (errorId != null) { - addErrorMessageToJson(errorJson, errorMessage, errorId); - } else { - addErrorMessageToJson(errorJson, errorMessage); - } + addErrorMessageToJson(errorJson, initialAction, errorMessage, errorId); VpnStatus.logWarning("[API] error: " + errorMessage); result.putString(ERRORS, errorJson.toString()); result.putBoolean(BROADCAST_RESULT_KEY, false); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java index 710aee0f..712ee172 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java @@ -67,8 +67,9 @@ public class ProviderApiSetupBroadcastReceiver extends BroadcastReceiver { case ProviderAPI.PROVIDER_OK: setupInterface.handleProviderSetUp(handledProvider); break; + case ProviderAPI.TOR_TIMEOUT: case ProviderAPI.PROVIDER_NOK: - setupInterface.handleProviderSetupFailed(resultData); + setupInterface.handleError(resultData); break; case ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE: setupInterface.handleCorrectlyDownloadedCertificate(handledProvider); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupFailedDialog.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupFailedDialog.java index 947d1182..50c063b2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupFailedDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupFailedDialog.java @@ -21,19 +21,25 @@ import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; import org.json.JSONObject; -import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.base.models.Provider; +import se.leap.bitmaskclient.base.utils.PreferenceHelper; -import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.DEFAULT; -import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.valueOf; import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORID; import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.INITIAL_ACTION; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.SET_UP_PROVIDER; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_PROVIDER_DETAILS; +import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.DEFAULT; +import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.valueOf; /** * Implements a dialog to show why a download failed. @@ -43,11 +49,13 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; public class ProviderSetupFailedDialog extends DialogFragment { public static String TAG = "downloaded_failed_dialog"; - private final static String KEY_PROVIDER = "key provider"; - private final static String KEY_REASON_TO_FAIL = "key reason to fail"; - private final static String KEY_DOWNLOAD_ERROR = "key download error"; + private final static String KEY_PROVIDER = "key_provider"; + private final static String KEY_REASON_TO_FAIL = "key_reason_to_fail"; + private final static String KEY_DOWNLOAD_ERROR = "key_download_error"; + private final static String KEY_INITAL_ACTION = "key_inital_action"; private String reasonToFail; private DOWNLOAD_ERRORS downloadError = DEFAULT; + private String initialAction; private Provider provider; @@ -59,7 +67,8 @@ public class ProviderSetupFailedDialog extends DialogFragment { ERROR_CORRUPTED_PROVIDER_JSON, ERROR_INVALID_CERTIFICATE, ERROR_CERTIFICATE_PINNING, - ERROR_NEW_URL_NO_VPN_PROVIDER + ERROR_NEW_URL_NO_VPN_PROVIDER, + ERROR_TOR_TIMEOUT } /** @@ -91,6 +100,10 @@ public class ProviderSetupFailedDialog extends DialogFragment { } else if (testNewURL) { dialogFragment.downloadError = DOWNLOAD_ERRORS.ERROR_NEW_URL_NO_VPN_PROVIDER; } + + if (errorJson.has(INITIAL_ACTION)) { + dialogFragment.initialAction = errorJson.getString(INITIAL_ACTION); + } } catch (Exception e) { e.printStackTrace(); dialogFragment.reasonToFail = dialogFragment.getString(R.string.error_io_exception_user_message); @@ -125,6 +138,14 @@ public class ProviderSetupFailedDialog extends DialogFragment { builder.setPositiveButton(R.string.retry, (dialog, id) -> interfaceWithConfigurationWizard.addAndSelectNewProvider(provider.getMainUrlString())); break; + case ERROR_TOR_TIMEOUT: + builder.setPositiveButton(R.string.retry, (dialog, id) -> { + handleTorTimeoutError(); + }); + builder.setNeutralButton(R.string.retry_unobfuscated, ((dialog, id) -> { + PreferenceHelper.useBridges(getContext(), false); + handleTorTimeoutError(); + })); default: builder.setPositiveButton(R.string.retry, (dialog, id) -> interfaceWithConfigurationWizard.retrySetUpProvider(provider)); @@ -135,6 +156,20 @@ public class ProviderSetupFailedDialog extends DialogFragment { return builder.create(); } + private void handleTorTimeoutError() { + switch (initialAction) { + case SET_UP_PROVIDER: + case UPDATE_PROVIDER_DETAILS: + interfaceWithConfigurationWizard.retrySetUpProvider(provider); + break; + case UPDATE_INVALID_VPN_CERTIFICATE: + ProviderAPICommand.execute(getContext(), UPDATE_INVALID_VPN_CERTIFICATE, provider); + break; + default: + break; + } + } + public interface DownloadFailedDialogInterface { void retrySetUpProvider(@NonNull Provider provider); @@ -170,6 +205,7 @@ public class ProviderSetupFailedDialog extends DialogFragment { outState.putParcelable(KEY_PROVIDER, provider); outState.putString(KEY_REASON_TO_FAIL, reasonToFail); outState.putString(KEY_DOWNLOAD_ERROR, downloadError.toString()); + outState.putString(KEY_INITAL_ACTION, initialAction); } private void restoreFromSavedInstance(Bundle savedInstanceState) { @@ -185,5 +221,8 @@ public class ProviderSetupFailedDialog extends DialogFragment { if (savedInstanceState.containsKey(KEY_DOWNLOAD_ERROR)) { this.downloadError = valueOf(savedInstanceState.getString(KEY_DOWNLOAD_ERROR)); } + if (savedInstanceState.containsKey(KEY_INITAL_ACTION)) { + this.initialAction = savedInstanceState.getString(KEY_INITAL_ACTION); + } } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupInterface.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupInterface.java index 5b5c94b4..0c60a3ce 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupInterface.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupInterface.java @@ -35,7 +35,7 @@ public interface ProviderSetupInterface { } void handleProviderSetUp(Provider provider); - void handleProviderSetupFailed(Bundle resultData); + void handleError(Bundle resultData); void handleCorrectlyDownloadedCertificate(Provider provider); void handleIncorrectlyDownloadedCertificate(); Provider getProvider(); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java index 6395c7ae..7628dfcb 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java @@ -145,7 +145,7 @@ public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity } @Override - public void handleProviderSetupFailed(Bundle resultData) { + public void handleError(Bundle resultData) { reasonToFail = resultData.getString(ERRORS); showDownloadFailedDialog(); } -- cgit v1.2.3 From 7b2f2432edf3f2b4c66aa95d398c65de63da6f46 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 6 Nov 2021 00:24:08 +0100 Subject: hide connection detail UI on error handling --- .../activities/ConfigWizardBaseActivity.java | 15 ++++++++++++--- .../activities/ProviderSetupBaseActivity.java | 4 ++++ 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java index a0c046de..930c0f73 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java @@ -31,6 +31,7 @@ import java.util.Observable; import java.util.Observer; import butterknife.BindView; +import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.views.ProviderHeaderView; @@ -218,6 +219,16 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple providerHeaderView.setTitle(providerHeaderText); } + protected void hideConnectionDetails() { + if (loadingScreen == null) { + return; + } + + connectionDetailBtn.setVisibility(VISIBLE); + connectionDetailContainer.setVisibility(GONE); + logsContainer.setVisibility(GONE); + } + protected void showConnectionDetails() { if (loadingScreen == null) { return; @@ -257,9 +268,7 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple if (loadingScreen == null) { return; } - connectionDetailBtn.setVisibility(VISIBLE); - connectionDetailContainer.setVisibility(GONE); - logsContainer.setVisibility(GONE); + hideConnectionDetails(); loadingScreen.setVisibility(GONE); content.setVisibility(VISIBLE); } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java index 7628dfcb..a9f773c3 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java @@ -20,6 +20,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.util.Log; +import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -89,9 +90,11 @@ public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity showProgressBar(); } else if (PENDING_SHOW_FAILED_DIALOG == providerConfigState) { showProgressBar(); + hideConnectionDetails(); showDownloadFailedDialog(); } else if (SHOW_FAILED_DIALOG == providerConfigState) { showProgressBar(); + hideConnectionDetails(); } else if (SHOWING_PROVIDER_DETAILS == providerConfigState) { cancelSettingUpProvider(false); } else if (PENDING_SHOW_PROVIDER_DETAILS == providerConfigState) { @@ -229,6 +232,7 @@ public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity public void showDownloadFailedDialog() { try { providerConfigState = SHOW_FAILED_DIALOG; + hideConnectionDetails(); FragmentTransaction fragmentTransaction = fragmentManager.removePreviousFragment(ProviderSetupFailedDialog.TAG); DialogFragment newFragment; try { -- cgit v1.2.3 From 9c45fdb51b639d9c2b638edc70f8af7de6ff90ff Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 6 Nov 2021 00:24:37 +0100 Subject: fix app crash on pre Android 7 --- .../providersetup/activities/ConfigWizardBaseActivity.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java index 930c0f73..12c237c5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java @@ -299,8 +299,11 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple if (loadingScreen == null) { return; } - - progressBar.setProgress(value, true); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + progressBar.setProgress(value); + } else { + progressBar.setProgress(value, true); + } progressBar.setIndeterminate(value >= 100 || value < 0); } -- cgit v1.2.3 From 319a2fa28a148b6aeee27dd1304f6d99a96998ab Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 6 Nov 2021 00:27:07 +0100 Subject: fix potential memory leak --- .../leap/bitmaskclient/providersetup/ProviderSetupFailedDialog.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupFailedDialog.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupFailedDialog.java index 50c063b2..a9247807 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupFailedDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupFailedDialog.java @@ -193,6 +193,12 @@ public class ProviderSetupFailedDialog extends DialogFragment { } } + @Override + public void onDetach() { + super.onDetach(); + interfaceWithConfigurationWizard = null; + } + @Override public void onCancel(DialogInterface dialog) { dialog.dismiss(); -- cgit v1.2.3 From 8a7b455f011842d17de687b7cbb2b6589b78ac3f Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 6 Nov 2021 00:52:23 +0100 Subject: initiate tor status logs with empty strings --- .../main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index eca0f555..3be4ce12 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -52,8 +52,8 @@ public class TorStatusObservable extends Observable { private SnowflakeStatus snowflakeStatus = SnowflakeStatus.OFF; private final TorNotificationManager torNotificationManager; private String lastError; - private String lastTorLog; - private String lastSnowflakeLog; + private String lastTorLog = ""; + private String lastSnowflakeLog = ""; private int port = -1; private int bootstrapPercent = -1; private Vector lastLogs = new Vector<>(100); @@ -253,7 +253,7 @@ public class TorStatusObservable extends Observable { case OFF: break; } - return null; + return ""; } public static void shutdownTor(Context context) { -- cgit v1.2.3 From eb434ae79f45dfd5c14c0901c414a287221442d4 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 6 Nov 2021 02:52:38 +0100 Subject: fix tor provider setup fallback mechanism --- .../bitmaskclient/base/utils/PreferenceHelper.java | 20 ++++++++------------ .../providersetup/ProviderApiManagerBase.java | 8 +++++--- 2 files changed, 13 insertions(+), 15 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java index 663e339e..7bbd032e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java @@ -35,6 +35,7 @@ import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.base.models.Constants.SHOW_EXPERIMENTAL; import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL; import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES; +import static se.leap.bitmaskclient.base.models.Constants.USE_TOR; /** * Created by cyberta on 18.03.18. @@ -152,11 +153,18 @@ public class PreferenceHelper { public static void useBridges(Context context, boolean isEnabled) { putBoolean(context, USE_BRIDGES, isEnabled); + putBoolean(context, USE_TOR, isEnabled); if (!isEnabled) { TorStatusObservable.setProxyPort(-1); } } + // in contrast to USE_BRIDGES, USE_TOR in enabled by default + // This way the initial provider setup can rely on tor as fallback circumvention mechanism + public static Boolean getUseTor(SharedPreferences preferences) { + return preferences.getBoolean(USE_TOR, true); + } + public static void saveBattery(Context context, boolean isEnabled) { putBoolean(context, DEFAULT_SHARED_PREFS_BATTERY_SAVER, isEnabled); } @@ -221,18 +229,6 @@ public class PreferenceHelper { putString(context, PREFERRED_CITY, city); } - /* public static Boolean useTor(SharedPreferences preferences) { - return preferences.getBoolean(USE_TOR, true); - } - - public static boolean useTor(Context context) { - return getBoolean(context, USE_TOR, true); - } - - public static void setUseTor(Context context, boolean useTor) { - putBoolean(context, USE_TOR, useTor); - }*/ - public static JSONObject getEipDefinitionFromPreferences(SharedPreferences preferences) { JSONObject result = new JSONObject(); try { diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 555eb21d..c385c4c4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -191,7 +191,9 @@ public abstract class ProviderApiManagerBase { } try { - startTorProxy(); + if (PreferenceHelper.getUseBridges(preferences)) { + startTorProxy(); + } } catch (InterruptedException | IllegalStateException e) { e.printStackTrace(); return; @@ -301,8 +303,8 @@ public abstract class ProviderApiManagerBase { } protected boolean startTorProxy() throws InterruptedException, IllegalStateException, TimeoutException { - if (PreferenceHelper.getUseBridges(preferences) && - EipStatus.getInstance().isDisconnected() && + if (EipStatus.getInstance().isDisconnected() && + PreferenceHelper.getUseTor(preferences) && serviceCallback.isConnectedToWifi() ) { serviceCallback.startTorService(); -- cgit v1.2.3 From c0a1ed833fdecabe4e228d084da51db6e64fadd6 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 6 Nov 2021 20:20:08 +0100 Subject: make default_url in DefaultedURL a local variable --- app/src/main/java/se/leap/bitmaskclient/base/models/DefaultedURL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/DefaultedURL.java b/app/src/main/java/se/leap/bitmaskclient/base/models/DefaultedURL.java index 4bb7e4ee..81f0d0c7 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/DefaultedURL.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/DefaultedURL.java @@ -5,12 +5,12 @@ import java.net.URL; public class DefaultedURL { private URL DEFAULT_URL; - private String default_url = "https://example.net"; private URL url; DefaultedURL() { try { + String default_url = "https://example.net"; DEFAULT_URL = new URL(default_url); url = DEFAULT_URL; } catch (MalformedURLException e) { -- cgit v1.2.3 From be0b23e395a4b37f80831ab527289dd124f25a84 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 6 Nov 2021 20:31:07 +0100 Subject: Keep preshipped and manually added provider urls as strings in ProviderManager, in order to avoid URL.equals() calls. Fixes also test. --- .../providersetup/ProviderManager.java | 27 ++++++++++------------ 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java index 654fb8e2..88413087 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java @@ -1,18 +1,15 @@ package se.leap.bitmaskclient.providersetup; import android.content.res.AssetManager; + import androidx.annotation.VisibleForTesting; import com.pedrogomez.renderers.AdapteeCollection; -import org.json.JSONException; -import org.json.JSONObject; - import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -44,8 +41,8 @@ public class ProviderManager implements AdapteeCollection { private File externalFilesDir; private Set defaultProviders; private Set customProviders; - private Set defaultProviderURLs; - private Set customProviderURLs; + private Set defaultProviderURLs; + private Set customProviderURLs; private static ProviderManager instance; @@ -76,10 +73,10 @@ public class ProviderManager implements AdapteeCollection { } } - private Set getProviderUrlSetFromProviderSet(Set providers) { - HashSet providerUrls = new HashSet<>(); + private Set getProviderUrlSetFromProviderSet(Set providers) { + HashSet providerUrls = new HashSet<>(); for (Provider provider : providers) { - providerUrls.add(provider.getMainUrl().getUrl()); + providerUrls.add(provider.getMainUrl().toString()); } return providerUrls; } @@ -167,16 +164,16 @@ public class ProviderManager implements AdapteeCollection { @Override public boolean add(Provider element) { return element != null && - !defaultProviderURLs.contains(element.getMainUrl().getUrl()) && + !defaultProviderURLs.contains(element.getMainUrl().toString()) && customProviders.add(element) && - customProviderURLs.add(element.getMainUrl().getUrl()); + customProviderURLs.add(element.getMainUrl().toString()); } @Override public boolean remove(Object element) { return element instanceof Provider && customProviders.remove(element) && - customProviderURLs.remove(((Provider) element).getMainUrl().getUrl()); + customProviderURLs.remove(((Provider) element).getMainUrl().toString()); } @Override @@ -186,7 +183,7 @@ public class ProviderManager implements AdapteeCollection { while (iterator.hasNext()) { Provider p = (Provider) iterator.next(); addedAll = customProviders.add(p) && - customProviderURLs.add(p.getMainUrl().getUrl()) && + customProviderURLs.add(p.getMainUrl().toString()) && addedAll; } return addedAll; @@ -199,8 +196,8 @@ public class ProviderManager implements AdapteeCollection { try { while (iterator.hasNext()) { Provider p = (Provider) iterator.next(); - removedAll = ((defaultProviders.remove(p) && defaultProviderURLs.remove(p.getMainUrl().getUrl())) || - (customProviders.remove(p) && customProviderURLs.remove(p.getMainUrl().getUrl()))) && + removedAll = ((defaultProviders.remove(p) && defaultProviderURLs.remove(p.getMainUrl().toString())) || + (customProviders.remove(p) && customProviderURLs.remove(p.getMainUrl().toString()))) && removedAll; } } catch (ClassCastException e) { -- cgit v1.2.3 From 6511de56528daa7348ebfa1c143f3373740f5442 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 6 Nov 2021 20:32:10 +0100 Subject: add little comment about the meaning of providerIp and providerApiIp --- app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java index 5d8b4e5d..974aef80 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java @@ -53,8 +53,8 @@ public final class Provider implements Parcelable { private DefaultedURL mainUrl = new DefaultedURL(); private DefaultedURL apiUrl = new DefaultedURL(); private DefaultedURL geoipUrl = new DefaultedURL(); - private String providerIp = ""; - private String providerApiIp = ""; + private String providerIp = ""; // ip of the provider main url + private String providerApiIp = ""; // ip of the provider api url private String certificatePin = ""; private String certificatePinEncoding = ""; private String caCert = ""; -- cgit v1.2.3 From 2bb2713ec024e687a563adcb706ca9544e4a8b84 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 7 Nov 2021 04:58:10 +0100 Subject: catch possible IllegalStateException within stopService --- .../java/se/leap/bitmaskclient/providersetup/ProviderAPI.java | 11 ++++++++--- .../bitmaskclient/providersetup/ProviderApiManagerBase.java | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index 65810861..335d70b2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -175,10 +175,15 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB } @Override - public void stopTorService() throws IllegalStateException { + public void stopTorService() { closeTorServiceConnection(); - Intent stopIntent = new Intent(this, TorService.class); - stopService(stopIntent); + try { + Intent stopIntent = new Intent(this, TorService.class); + stopService(stopIntent); + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index c385c4c4..0853f96d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -150,7 +150,7 @@ public abstract class ProviderApiManagerBase { public interface ProviderApiServiceCallback { void broadcastEvent(Intent intent); void startTorService() throws InterruptedException, IllegalStateException; - void stopTorService() throws IllegalStateException; + void stopTorService(); int getTorHttpTunnelPort(); boolean isConnectedToWifi(); } -- cgit v1.2.3 From 7ece2b7cf81ac1e69003f288fc15f7d56ab9ca25 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 7 Nov 2021 04:59:50 +0100 Subject: implement tor fallback mechanism for canConnect() --- .../providersetup/ProviderApiManagerBase.java | 23 +++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 0853f96d..0c09aec1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -135,6 +135,7 @@ import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWN import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON; import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_INVALID_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_TOR_TIMEOUT; +import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.ON; import static se.leap.bitmaskclient.tor.TorStatusObservable.getProxyPort; @@ -737,6 +738,10 @@ public abstract class ProviderApiManagerBase { } private boolean canConnect(Provider provider, Bundle result) { + return canConnect(provider, result, 0); + } + + private boolean canConnect(Provider provider, Bundle result, int tries) { JSONObject errorJson = new JSONObject(); String providerUrl = provider.getApiUrlString() + "/provider.json"; @@ -746,8 +751,11 @@ public abstract class ProviderApiManagerBase { return false; } - try { + if (tries > 0) { + result.remove(ERRORS); + } + try { return ProviderApiConnector.canConnect(okHttpClient, providerUrl); } catch (UnknownHostException | SocketTimeoutException e) { @@ -773,6 +781,19 @@ public abstract class ProviderApiManagerBase { VpnStatus.logWarning("[API] IOException during connection check: " + e.getLocalizedMessage()); setErrorResult(result, error_io_exception_user_message, null); } + + try { + if (tries == 0 && + result.containsKey(ERRORS) && + TorStatusObservable.getStatus() == OFF && + startTorProxy() + ) { + return canConnect(provider, result, 1); + } + } catch (InterruptedException | IllegalStateException | TimeoutException e) { + e.printStackTrace(); + } + return false; } -- cgit v1.2.3 From 7bde8bbb733dfcba7baace5c2261f67da8e0d3d0 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 7 Nov 2021 05:20:25 +0100 Subject: Add provider setup unit tests wrt. Tor handling --- .../main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index 3be4ce12..fae7d063 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -83,8 +83,9 @@ public class TorStatusObservable extends Observable { * @param timeout Timout in seconds * @throws InterruptedException if thread was interrupted while waiting * @throws TimeoutException thrown if timeout was reached + * @return true return value only needed to mock this method call */ - public static void waitUntil(StatusCondition condition, int timeout) throws InterruptedException, TimeoutException { + public static boolean waitUntil(StatusCondition condition, int timeout) throws InterruptedException, TimeoutException { CountDownLatch countDownLatch = new CountDownLatch(1); final AtomicBoolean conditionMet = new AtomicBoolean(false); Observer observer = (o, arg) -> { @@ -95,7 +96,7 @@ public class TorStatusObservable extends Observable { }; if (condition.met()) { // no need to wait - return; + return true; } getInstance().addObserver(observer); countDownLatch.await(timeout, TimeUnit.SECONDS); @@ -103,6 +104,7 @@ public class TorStatusObservable extends Observable { if (!conditionMet.get()) { throw new TimeoutException("Status condition not met within " + timeout + "s."); } + return true; } public static void logSnowflakeMessage(Context context, String message) { -- cgit v1.2.3 From 840b2ca0dea22bba983698d832d3f4d1e7efacf8 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 7 Nov 2021 18:41:09 +0100 Subject: always reset proxy port if tor status turns to OFF --- app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java | 1 + 1 file changed, 1 insertion(+) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index fae7d063..2527ce83 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -160,6 +160,7 @@ public class TorStatusObservable extends Observable { if (getInstance().status == TorStatus.OFF) { getInstance().torNotificationManager.cancelNotifications(context); getInstance().cancelled = false; + getInstance().port = -1; } else { if (logKey != null) { getInstance().lastTorLog = getStringFor(context, logKey); -- cgit v1.2.3 From 6ef5241baf6a1fa2bc4e6f3ecd805edf4827e712 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 7 Nov 2021 19:54:46 +0100 Subject: tweak loading screen - hide connection details behind a clickable lable --- .../activities/ConfigWizardBaseActivity.java | 27 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java index 12c237c5..546beb18 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java @@ -71,7 +71,15 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple @Nullable @BindView(R.id.btn_connection_detail) - protected Button connectionDetailBtn; + protected AppCompatTextView connectionDetailBtn; + + @Nullable + @BindView(R.id.connection_detail_header_container) + protected RelativeLayout connectionDetailHeaderContainer; + + @Nullable + @BindView(R.id.connection_details_title) + protected AppCompatTextView connectionDetailsTitle; @Nullable @BindView(R.id.connection_detail_container) @@ -224,7 +232,7 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple return; } - connectionDetailBtn.setVisibility(VISIBLE); + connectionDetailHeaderContainer.setVisibility(GONE); connectionDetailContainer.setVisibility(GONE); logsContainer.setVisibility(GONE); } @@ -254,10 +262,19 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple snowflakeState.setText(getLastSnowflakeLog()); torState.setText(getLastTorLog()); connectionDetailBtn.setOnClickListener(v -> { - connectionDetailBtn.setVisibility(GONE); - logsContainer.setVisibility(VISIBLE); + if (logsContainer.getVisibility() == VISIBLE) { + logsContainer.setVisibility(GONE); + connectionDetailContainer.setVisibility(GONE); + connectionDetailsTitle.setVisibility(GONE); + connectionDetailBtn.setText(R.string.show_connection_details); + } else { + logsContainer.setVisibility(VISIBLE); + connectionDetailContainer.setVisibility(VISIBLE); + connectionDetailsTitle.setVisibility(VISIBLE); + connectionDetailBtn.setText(R.string.hide_connection_details); + } }); - connectionDetailContainer.setVisibility(VISIBLE); + connectionDetailHeaderContainer.setVisibility(VISIBLE); } private int getFirstVisibleItemPosion() { -- cgit v1.2.3 From 62c28b219a85aa3074356e1e49e92e30c1166c3b Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 7 Nov 2021 22:45:29 +0100 Subject: tweak log item cell, get rid of DividerItemDecorator and use simple view as separator per cell, fixes cell height and text positioning issues --- .../bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java | 1 - 1 file changed, 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java index 546beb18..a4104e30 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java @@ -243,7 +243,6 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple } LinearLayoutManager layoutManager = new LinearLayoutManager(this); connectionDetailLogs.setLayoutManager(layoutManager); - connectionDetailLogs.addItemDecoration( new DividerItemDecoration(this, layoutManager.getOrientation())); torLogAdapter = new TorLogAdapter(getLastLogs()); connectionDetailLogs.setAdapter(torLogAdapter); -- cgit v1.2.3 From 0b80fad26c91e5aa0faf8bc0132184eeeb7883b0 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Mon, 8 Nov 2021 00:54:24 +0100 Subject: revert restriction to be connected to wifi in order to use snowflake/tor fallback --- .../main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java | 5 ----- .../se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java | 4 +--- 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index 335d70b2..c45d7ae9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -154,11 +154,6 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } - @Override - public boolean isConnectedToWifi() { - return NetworkUtils.isConnectedToWifi(getApplicationContext()); - } - @Override public void startTorService() throws InterruptedException, IllegalStateException { initTorServiceConnection(this); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 0c09aec1..7872fb32 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -153,7 +153,6 @@ public abstract class ProviderApiManagerBase { void startTorService() throws InterruptedException, IllegalStateException; void stopTorService(); int getTorHttpTunnelPort(); - boolean isConnectedToWifi(); } private final ProviderApiServiceCallback serviceCallback; @@ -305,8 +304,7 @@ public abstract class ProviderApiManagerBase { protected boolean startTorProxy() throws InterruptedException, IllegalStateException, TimeoutException { if (EipStatus.getInstance().isDisconnected() && - PreferenceHelper.getUseTor(preferences) && - serviceCallback.isConnectedToWifi() + PreferenceHelper.getUseTor(preferences) ) { serviceCallback.startTorService(); waitForTorCircuits(); -- cgit v1.2.3 From 7cd76c3eb08f89be94642a57eca7d929d8d72c6d Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 9 Nov 2021 23:33:55 +0100 Subject: check tor preferences before initiating a tor service connection --- .../main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java | 4 ++++ .../main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java index 7bbd032e..06fb25e9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java @@ -165,6 +165,10 @@ public class PreferenceHelper { return preferences.getBoolean(USE_TOR, true); } + public static Boolean getUseTor(Context context) { + return getBoolean(context, USE_TOR, true); + } + public static void saveBattery(Context context, boolean isEnabled) { putBoolean(context, DEFAULT_SHARED_PREFS_BATTERY_SAVER, isEnabled); } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index c45d7ae9..94d3e0de 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -212,7 +212,7 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB * @throws IllegalStateException thrown if this method was not called from a background thread */ private void initTorServiceConnection(Context context) throws InterruptedException, IllegalStateException { - if (PreferenceHelper.getUseBridges(context)) { + if (PreferenceHelper.getUseTor(context)) { if (torServiceConnection == null) { Log.d(TAG, "serviceConnection is still null"); if (!TorService.hasClientTransportPlugin()) { -- cgit v1.2.3 From c38240b5776cc2e5b1057652787367ffb80eb5a1 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 9 Nov 2021 23:35:21 +0100 Subject: debounce tor notifications to max. 2 per second --- .../se/leap/bitmaskclient/tor/TorNotificationManager.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java index 507de4ae..3f3fbf4f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorNotificationManager.java @@ -30,6 +30,9 @@ import se.leap.bitmaskclient.R; public class TorNotificationManager { public final static int TOR_SERVICE_NOTIFICATION_ID = 10; static final String NOTIFICATION_CHANNEL_NEWSTATUS_ID = "bitmask_tor_service_news"; + private long lastNotificationTime = 0; + // debounce timeout in milliseconds + private final static long NOTIFICATION_DEBOUNCE_TIME = 500; public TorNotificationManager() {} @@ -48,6 +51,9 @@ public class TorNotificationManager { } public void buildTorNotification(Context context, String state, String message, int progress) { + if (shouldDropNotification()) { + return; + } NotificationManager notificationManager = initNotificationManager(context); if (notificationManager == null) { return; @@ -69,6 +75,15 @@ public class TorNotificationManager { notificationManager.notify(TOR_SERVICE_NOTIFICATION_ID, notificationBuilder.build()); } + private boolean shouldDropNotification() { + long now = System.currentTimeMillis(); + if (now - lastNotificationTime < NOTIFICATION_DEBOUNCE_TIME) { + return true; + } + lastNotificationTime = now; + return false; + } + private static NotificationManager initNotificationManager(Context context) { NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); -- cgit v1.2.3 From 599e93addd79f51959009df558accfa66b6bc15d Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 10 Nov 2021 02:21:44 +0100 Subject: move optional arguments to the back in ProviderAPI's error handling methods --- .../bitmaskclient/providersetup/ProviderApiManagerBase.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 7872fb32..dc15e578 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -200,7 +200,7 @@ public abstract class ProviderApiManagerBase { } catch (TimeoutException e) { serviceCallback.stopTorService(); Bundle result = new Bundle(); - setErrorResult(result, action, R.string.error_tor_timeout, ERROR_TOR_TIMEOUT.toString()); + setErrorResult(result, R.string.error_tor_timeout, ERROR_TOR_TIMEOUT.toString(), action); sendToReceiverOrBroadcast(receiver, TOR_TIMEOUT, result, provider); return; } @@ -359,7 +359,7 @@ public abstract class ProviderApiManagerBase { } } - private void addErrorMessageToJson(JSONObject jsonObject, String initialAction, String errorMessage, String errorId) { + private void addErrorMessageToJson(JSONObject jsonObject, String errorMessage, String errorId, String initialAction) { try { jsonObject.put(ERRORS, errorMessage); jsonObject.putOpt(ERRORID, errorId); @@ -940,13 +940,13 @@ public abstract class ProviderApiManagerBase { } Bundle setErrorResult(Bundle result, int errorMessageId, String errorId) { - return setErrorResult(result, null, errorMessageId, errorId); + return setErrorResult(result, errorMessageId, errorId, null); } - Bundle setErrorResult(Bundle result, String initialAction, int errorMessageId, String errorId) { + Bundle setErrorResult(Bundle result, int errorMessageId, String errorId, String initialAction) { JSONObject errorJson = new JSONObject(); String errorMessage = getProviderFormattedString(resources, errorMessageId); - addErrorMessageToJson(errorJson, initialAction, errorMessage, errorId); + addErrorMessageToJson(errorJson, errorMessage, errorId, initialAction); VpnStatus.logWarning("[API] error: " + errorMessage); result.putString(ERRORS, errorJson.toString()); result.putBoolean(BROADCAST_RESULT_KEY, false); -- cgit v1.2.3 From 1657571812f6585bd2883c97d114f8d9861505c0 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 10 Nov 2021 02:25:47 +0100 Subject: add a more specific error if provider api communication is attempted without any working internet connection --- .../bitmaskclient/providersetup/ProviderAPI.java | 32 ++++++++++++++++++++-- .../providersetup/ProviderApiManagerBase.java | 10 +++++++ .../ProviderApiSetupBroadcastReceiver.java | 1 + 3 files changed, 41 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index 94d3e0de..fb8d3e85 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -23,6 +23,9 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; import android.os.Build; import android.os.IBinder; import android.util.Log; @@ -37,7 +40,6 @@ import java.io.Closeable; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; -import de.blinkt.openvpn.core.NetworkUtils; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator; import se.leap.bitmaskclient.tor.ClientTransportPlugin; @@ -102,7 +104,8 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE = 16, CORRECTLY_DOWNLOADED_GEOIP_JSON = 17, INCORRECTLY_DOWNLOADED_GEOIP_JSON = 18, - TOR_TIMEOUT = 19; + TOR_TIMEOUT = 19, + MISSING_NETWORK_CONNECTION = 20; ProviderApiManager providerApiManager; private volatile TorServiceConnection torServiceConnection; @@ -198,6 +201,31 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB return -1; } + @Override + public boolean hasNetworkConnection() { + try { + ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); + return activeNetwork != null && + activeNetwork.isConnectedOrConnecting(); + } else { + NetworkCapabilities capabilities = cm.getNetworkCapabilities(cm.getActiveNetwork()); + if (capabilities != null) { + return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + } + return false; + } + } catch (RuntimeException e) { + e.printStackTrace(); + // we don't know, let's try to fetch data anyways then + return true; + } + } + + + private ProviderApiManager initApiManager() { SharedPreferences preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); OkHttpClientGenerator clientGenerator = new OkHttpClientGenerator(getResources()); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index dc15e578..8d626245 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -73,6 +73,7 @@ import static se.leap.bitmaskclient.R.string.error_io_exception_user_message; import static se.leap.bitmaskclient.R.string.error_json_exception_user_message; import static se.leap.bitmaskclient.R.string.error_no_such_algorithm_exception_user_message; import static se.leap.bitmaskclient.R.string.malformed_url; +import static se.leap.bitmaskclient.R.string.new_provider_uri; import static se.leap.bitmaskclient.R.string.server_unreachable_message; import static se.leap.bitmaskclient.R.string.service_is_down_error; import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid; @@ -118,6 +119,7 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.INITIAL_ACTION; import static se.leap.bitmaskclient.providersetup.ProviderAPI.LOGOUT_FAILED; import static se.leap.bitmaskclient.providersetup.ProviderAPI.LOG_IN; import static se.leap.bitmaskclient.providersetup.ProviderAPI.LOG_OUT; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.MISSING_NETWORK_CONNECTION; import static se.leap.bitmaskclient.providersetup.ProviderAPI.PARAMETERS; import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_NOK; import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_OK; @@ -153,6 +155,7 @@ public abstract class ProviderApiManagerBase { void startTorService() throws InterruptedException, IllegalStateException; void stopTorService(); int getTorHttpTunnelPort(); + boolean hasNetworkConnection(); } private final ProviderApiServiceCallback serviceCallback; @@ -190,6 +193,13 @@ public abstract class ProviderApiManagerBase { return; } + if (!serviceCallback.hasNetworkConnection()) { + Bundle result = new Bundle(); + setErrorResult(result, R.string.error_network_connection, null); + sendToReceiverOrBroadcast(receiver, MISSING_NETWORK_CONNECTION, result, provider); + return; + } + try { if (PreferenceHelper.getUseBridges(preferences)) { startTorProxy(); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java index 712ee172..cc6ff149 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java @@ -67,6 +67,7 @@ public class ProviderApiSetupBroadcastReceiver extends BroadcastReceiver { case ProviderAPI.PROVIDER_OK: setupInterface.handleProviderSetUp(handledProvider); break; + case ProviderAPI.MISSING_NETWORK_CONNECTION: case ProviderAPI.TOR_TIMEOUT: case ProviderAPI.PROVIDER_NOK: setupInterface.handleError(resultData); -- cgit v1.2.3 From 0b687502d047253ca50b691c29336bc3e53a29d2 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 11 Nov 2021 21:54:40 +0100 Subject: fix snowflake on-/off state detection --- .../main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index 2527ce83..ade22e6b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -114,9 +114,11 @@ public class TorStatusObservable extends Observable { getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), getNotificationLog(), getBootstrapProgress()); } //TODO: implement proper state signalling in IPtProxy - if (SNOWFLAKE_STARTED.equals(message)) { + if (SNOWFLAKE_STARTED.equals(message.trim())) { + Log.d(TAG, "snowflakeStatus ON"); getInstance().snowflakeStatus = SnowflakeStatus.ON; - } else if (SNOWFLAKE_STOPPED.equals(message)) { + } else if (SNOWFLAKE_STOPPED.equals(message.trim())) { + Log.d(TAG, "snowflakeStatus OFF"); getInstance().snowflakeStatus = SnowflakeStatus.OFF; } instance.setChanged(); -- cgit v1.2.3 From a917cbe977f640345677b97dc9b00900d78c46b3 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 11 Nov 2021 22:16:15 +0100 Subject: use command pattern to start/stop tor service, similar to EIP and ProviderAPI service --- .../leap/bitmaskclient/eip/EipSetupObserver.java | 7 +- .../bitmaskclient/providersetup/ProviderAPI.java | 137 ++------------------- .../providersetup/ProviderApiManagerBase.java | 7 +- .../activities/ProviderSetupBaseActivity.java | 3 +- .../leap/bitmaskclient/tor/TorServiceCommand.java | 123 ++++++++++++++++++ .../bitmaskclient/tor/TorServiceConnection.java | 73 +++++++++++ .../bitmaskclient/tor/TorStatusObservable.java | 11 +- 7 files changed, 217 insertions(+), 144 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java index 203885a1..023a1ce1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java @@ -44,6 +44,8 @@ import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.providersetup.ProviderAPI; import se.leap.bitmaskclient.providersetup.ProviderAPICommand; +import se.leap.bitmaskclient.tor.TorServiceCommand; +import se.leap.bitmaskclient.tor.TorServiceConnection; import se.leap.bitmaskclient.tor.TorStatusObservable; import static android.app.Activity.RESULT_CANCELED; @@ -213,8 +215,7 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta case INCORRECTLY_DOWNLOADED_EIP_SERVICE: case INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE: if (TorStatusObservable.getStatus() != OFF) { - Intent stopIntent = new Intent(context, TorService.class); - context.stopService(stopIntent); + TorServiceCommand.stopTorServiceAsync(context); } Log.d(TAG, "PROVIDER NOK - FETCH FAILED"); break; @@ -368,7 +369,7 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta observedProfileFromVpnStatus = null; this.changingGateway.set(changingGateway); if (TorStatusObservable.getStatus() != OFF) { - TorStatusObservable.shutdownTor(context); + TorServiceCommand.stopTorServiceAsync(context); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index fb8d3e85..709ca651 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -17,37 +17,25 @@ package se.leap.bitmaskclient.providersetup; import android.annotation.SuppressLint; -import android.app.Notification; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.os.Build; -import android.os.IBinder; -import android.util.Log; import androidx.annotation.NonNull; import androidx.core.app.JobIntentService; import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import org.torproject.jni.TorService; +import java.util.concurrent.TimeoutException; -import java.io.Closeable; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; - -import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator; -import se.leap.bitmaskclient.tor.ClientTransportPlugin; -import se.leap.bitmaskclient.tor.TorNotificationManager; +import se.leap.bitmaskclient.tor.TorServiceCommand; +import se.leap.bitmaskclient.tor.TorServiceConnection; import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread; -import static se.leap.bitmaskclient.tor.TorNotificationManager.TOR_SERVICE_NOTIFICATION_ID; /** * Implements HTTP api methods (encapsulated in {{@link ProviderApiManager}}) @@ -139,66 +127,24 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB providerApiManager.handleIntent(command); } - @Override - public void onDestroy() { - super.onDestroy(); - closeTorServiceConnection(); - } - - private void closeTorServiceConnection() { - if (torServiceConnection != null) { - torServiceConnection.close(); - torServiceConnection = null; - } - } - @Override public void broadcastEvent(Intent intent) { LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } @Override - public void startTorService() throws InterruptedException, IllegalStateException { - initTorServiceConnection(this); - Intent torServiceIntent = new Intent(this, TorService.class); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - Notification notification = TorNotificationManager.buildTorForegroundNotification(getApplicationContext()); - //noinspection NewApi - getApplicationContext().startForegroundService(torServiceIntent); - torServiceConnection.torService.startForeground(TOR_SERVICE_NOTIFICATION_ID, notification); - } else { - getApplicationContext().startService(torServiceIntent); - } + public boolean startTorService() throws InterruptedException, IllegalStateException, TimeoutException { + return TorServiceCommand.startTorService(this, null); } @Override public void stopTorService() { - closeTorServiceConnection(); - try { - Intent stopIntent = new Intent(this, TorService.class); - stopService(stopIntent); - } catch (IllegalStateException e) { - e.printStackTrace(); - } - + TorServiceCommand.stopTorService(this); } @Override public int getTorHttpTunnelPort() { - try { - initTorServiceConnection(this); - if (torServiceConnection != null) { - int tunnelPort = torServiceConnection.torService.getHttpTunnelPort(); - torServiceConnection.close(); - torServiceConnection = null; - return tunnelPort; - } - } catch (InterruptedException | IllegalStateException e) { - e.printStackTrace(); - } - - return -1; + return TorServiceCommand.getHttpTunnelPort(this); } @Override @@ -232,73 +178,4 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB return new ProviderApiManager(preferences, getResources(), clientGenerator, this); } - /** - * Assigns a new TorServiceConnection to ProviderAPI's member variable torServiceConnection. - * Only one thread at a time can create the service connection, that will be shared between threads - * - * @throws InterruptedException thrown if thread gets interrupted - * @throws IllegalStateException thrown if this method was not called from a background thread - */ - private void initTorServiceConnection(Context context) throws InterruptedException, IllegalStateException { - if (PreferenceHelper.getUseTor(context)) { - if (torServiceConnection == null) { - Log.d(TAG, "serviceConnection is still null"); - if (!TorService.hasClientTransportPlugin()) { - TorService.setClientTransportPlugin(new ClientTransportPlugin(context.getApplicationContext())); - } - torServiceConnection = new TorServiceConnection(context); - } - } - } - - public static class TorServiceConnection implements Closeable { - private final Context context; - private ServiceConnection serviceConnection; - private TorService torService; - - TorServiceConnection(Context context) throws InterruptedException, IllegalStateException { - this.context = context; - ensureNotOnMainThread(context); - Log.d(TAG, "initSynchronizedServiceConnection!"); - initSynchronizedServiceConnection(context); - } - - @Override - public void close() { - context.unbindService(serviceConnection); - } - - private void initSynchronizedServiceConnection(final Context context) throws InterruptedException { - final BlockingQueue blockingQueue = new LinkedBlockingQueue<>(1); - this.serviceConnection = new ServiceConnection() { - volatile boolean mConnectedAtLeastOnce = false; - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - if (!mConnectedAtLeastOnce) { - mConnectedAtLeastOnce = true; - try { - TorService.LocalBinder binder = (TorService.LocalBinder) service; - blockingQueue.put(binder.getService()); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - torService = null; - } - }; - Intent intent = new Intent(context, TorService.class); - context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); - torService = blockingQueue.take(); - } - - public TorService getService() { - return torService; - } - } - } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 8d626245..e2f98ca4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -152,7 +152,7 @@ public abstract class ProviderApiManagerBase { public interface ProviderApiServiceCallback { void broadcastEvent(Intent intent); - void startTorService() throws InterruptedException, IllegalStateException; + boolean startTorService() throws InterruptedException, IllegalStateException, TimeoutException; void stopTorService(); int getTorHttpTunnelPort(); boolean hasNetworkConnection(); @@ -314,9 +314,8 @@ public abstract class ProviderApiManagerBase { protected boolean startTorProxy() throws InterruptedException, IllegalStateException, TimeoutException { if (EipStatus.getInstance().isDisconnected() && - PreferenceHelper.getUseTor(preferences) - ) { - serviceCallback.startTorService(); + PreferenceHelper.getUseTor(preferences) && + serviceCallback.startTorService()) { waitForTorCircuits(); if (TorStatusObservable.isCancelled()) { throw new InterruptedException("Cancelled Tor setup."); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java index a9f773c3..e429f776 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderSetupBaseActivity.java @@ -40,6 +40,7 @@ import se.leap.bitmaskclient.providersetup.ProviderDetailActivity; import se.leap.bitmaskclient.providersetup.ProviderManager; import se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog; import se.leap.bitmaskclient.providersetup.ProviderSetupInterface; +import se.leap.bitmaskclient.tor.TorServiceCommand; import se.leap.bitmaskclient.tor.TorStatusObservable; import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_PROVIDER_API_EVENT; @@ -174,7 +175,7 @@ public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity public void cancelSettingUpProvider(boolean stopTor) { if (stopTor && TorStatusObservable.getStatus() != OFF) { Log.d(TAG, "SHUTDOWN - cancelSettingUpProvider stopTor:" + stopTor); - TorStatusObservable.shutdownTor(this); + TorServiceCommand.stopTorServiceAsync(this); } providerConfigState = PROVIDER_NOT_SET; provider = null; diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java new file mode 100644 index 00000000..1946b861 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java @@ -0,0 +1,123 @@ +package se.leap.bitmaskclient.tor; + +import android.app.Notification; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.util.Log; + +import androidx.annotation.WorkerThread; + +import org.torproject.jni.TorService; + +import java.util.concurrent.TimeoutException; + +import se.leap.bitmaskclient.base.utils.PreferenceHelper; + +import static se.leap.bitmaskclient.tor.TorNotificationManager.TOR_SERVICE_NOTIFICATION_ID; +import static se.leap.bitmaskclient.tor.TorStatusObservable.waitUntil; + +public class TorServiceCommand { + + + private static String TAG = TorServiceCommand.class.getSimpleName(); + + // we bind the service before starting it as foreground service so that we avoid startForeground related RemoteExceptions + @WorkerThread + public static boolean startTorService(Context context, String action) throws InterruptedException { + Log.d(TAG, "startTorService"); + try { + waitUntil(TorServiceCommand::isNotCancelled, 30); + } catch (TimeoutException e) { + e.printStackTrace(); + } + TorServiceConnection torServiceConnection = initTorServiceConnection(context); + Log.d(TAG, "startTorService foreground: " + (torServiceConnection != null)); + boolean startedForeground = false; + if (torServiceConnection == null) { + return startedForeground; + } + + try { + Intent torServiceIntent = new Intent(context, TorService.class); + torServiceIntent.setAction(action); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Notification notification = TorNotificationManager.buildTorForegroundNotification(context.getApplicationContext()); + //noinspection NewApi + context.getApplicationContext().startForegroundService(torServiceIntent); + torServiceConnection.getService().startForeground(TOR_SERVICE_NOTIFICATION_ID, notification); + } else { + context.getApplicationContext().startService(torServiceIntent); + } + startedForeground = true; + } catch (IllegalStateException e) { + e.printStackTrace(); + } + + if (torServiceConnection != null) { + torServiceConnection.close(); + } + + return startedForeground; + } + + @WorkerThread + public static void stopTorService(Context context) { + if (TorStatusObservable.getStatus() == TorStatusObservable.TorStatus.OFF) { + return; + } + TorStatusObservable.markCancelled(); + + try { + Intent torServiceIntent = new Intent(context, TorService.class); + torServiceIntent.setAction(TorService.ACTION_STOP); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + //noinspection NewApi + context.getApplicationContext().startService(torServiceIntent); + } else { + context.getApplicationContext().startService(torServiceIntent); + } + } catch (IllegalStateException e) { + e.printStackTrace(); + } + } + + public static void stopTorServiceAsync(Context context) { + TorStatusObservable.markCancelled(); + new Thread(() -> stopTorService(context)).start(); + } + + @WorkerThread + public static int getHttpTunnelPort(Context context) { + try { + TorServiceConnection torServiceConnection = initTorServiceConnection(context); + if (torServiceConnection != null) { + int tunnelPort = torServiceConnection.getService().getHttpTunnelPort(); + torServiceConnection.close(); + return tunnelPort; + } + } catch (InterruptedException | IllegalStateException e) { + e.printStackTrace(); + } + return -1; + } + + private static boolean isNotCancelled() { + return !TorStatusObservable.isCancelled(); + } + + + private static TorServiceConnection initTorServiceConnection(Context context) throws InterruptedException, IllegalStateException { + Log.d(TAG, "initTorServiceConnection"); + if (PreferenceHelper.getUseTor(context)) { + Log.d(TAG, "serviceConnection is still null"); + if (!TorService.hasClientTransportPlugin()) { + TorService.setClientTransportPlugin(new ClientTransportPlugin(context.getApplicationContext())); + } + return new TorServiceConnection(context); + } + return null; + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java new file mode 100644 index 00000000..0154983a --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java @@ -0,0 +1,73 @@ +package se.leap.bitmaskclient.tor; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.util.Log; + +import androidx.annotation.WorkerThread; + +import org.torproject.jni.TorService; + +import java.io.Closeable; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +import se.leap.bitmaskclient.providersetup.ProviderAPI; + +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread; + +public class TorServiceConnection implements Closeable { + private static final String TAG = TorServiceConnection.class.getSimpleName(); + private final Context context; + private ServiceConnection serviceConnection; + private TorService torService; + + @WorkerThread + public TorServiceConnection(Context context) throws InterruptedException, IllegalStateException { + this.context = context; + ensureNotOnMainThread(context); + initSynchronizedServiceConnection(context); + } + + @Override + public void close() { + context.unbindService(serviceConnection); + } + + private void initSynchronizedServiceConnection(final Context context) throws InterruptedException { + Log.d(TAG, "initSynchronizedServiceConnection"); + final BlockingQueue blockingQueue = new LinkedBlockingQueue<>(1); + this.serviceConnection = new ServiceConnection() { + volatile boolean mConnectedAtLeastOnce = false; + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (!mConnectedAtLeastOnce) { + mConnectedAtLeastOnce = true; + Log.d(TAG, "onServiceConnected"); + try { + TorService.LocalBinder binder = (TorService.LocalBinder) service; + blockingQueue.put(binder.getService()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + torService = null; + } + }; + Intent intent = new Intent(context, TorService.class); + context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); + torService = blockingQueue.take(); + } + + public TorService getService() { + return torService; + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index ade22e6b..d426d51e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -261,12 +261,11 @@ public class TorStatusObservable extends Observable { return ""; } - public static void shutdownTor(Context context) { - getInstance().cancelled = true; - getInstance().notifyObservers(); - - Intent intent = new Intent(context, TorService.class); - context.stopService(intent); + public static void markCancelled() { + if (!getInstance().cancelled) { + getInstance().cancelled = true; + getInstance().notifyObservers(); + } } public static boolean isCancelled() { -- cgit v1.2.3 From 0728a708d8a4d7abc9cb28a0c19a8856b3b285d4 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 11 Nov 2021 23:30:32 +0100 Subject: Check if snowflake stopped with an error. Change state to OFF in that case, too --- .../java/se/leap/bitmaskclient/tor/TorStatusObservable.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index d426d51e..cde17c34 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -1,13 +1,10 @@ package se.leap.bitmaskclient.tor; import android.content.Context; -import android.content.Intent; import android.util.Log; import androidx.annotation.Nullable; -import org.torproject.jni.TorService; - import java.util.Observable; import java.util.Observer; import java.util.Vector; @@ -45,7 +42,9 @@ public class TorStatusObservable extends Observable { public static final String LOG_TAG_TOR = "[TOR]"; public static final String LOG_TAG_SNOWFLAKE = "[SNOWFLAKE]"; public static final String SNOWFLAKE_STARTED = "--- Starting Snowflake Client ---"; - public static final String SNOWFLAKE_STOPPED = "---- SnowflakeConn: end collecting snowflakes ---"; + public static final String SNOWFLAKE_STOPPED_COLLECTING = "---- SnowflakeConn: end collecting snowflakes ---"; + public static final String SNOWFLAKE_COPY_LOOP_STOPPED = "copy loop ended"; + public static final String SNOWFLAKE_SOCKS_ERROR = "SOCKS accept error"; private static TorStatusObservable instance; private TorStatus status = TorStatus.OFF; @@ -117,7 +116,9 @@ public class TorStatusObservable extends Observable { if (SNOWFLAKE_STARTED.equals(message.trim())) { Log.d(TAG, "snowflakeStatus ON"); getInstance().snowflakeStatus = SnowflakeStatus.ON; - } else if (SNOWFLAKE_STOPPED.equals(message.trim())) { + } else if (SNOWFLAKE_STOPPED_COLLECTING.equals(message.trim()) || + SNOWFLAKE_COPY_LOOP_STOPPED.equals(message.trim()) || + message.trim().contains(SNOWFLAKE_SOCKS_ERROR)) { Log.d(TAG, "snowflakeStatus OFF"); getInstance().snowflakeStatus = SnowflakeStatus.OFF; } -- cgit v1.2.3 From 82342c023f7cc08b959bb980c3acd8f11eb808c1 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 12 Nov 2021 01:36:46 +0100 Subject: cleanup --- .../java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java | 1 - 1 file changed, 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index e2f98ca4..52046e07 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -73,7 +73,6 @@ import static se.leap.bitmaskclient.R.string.error_io_exception_user_message; import static se.leap.bitmaskclient.R.string.error_json_exception_user_message; import static se.leap.bitmaskclient.R.string.error_no_such_algorithm_exception_user_message; import static se.leap.bitmaskclient.R.string.malformed_url; -import static se.leap.bitmaskclient.R.string.new_provider_uri; import static se.leap.bitmaskclient.R.string.server_unreachable_message; import static se.leap.bitmaskclient.R.string.service_is_down_error; import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid; -- cgit v1.2.3 From 8aeb4791b6e024de9aa9c61b574d8c798a3c0a2c Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 12 Nov 2021 01:41:10 +0100 Subject: add licenses --- .../leap/bitmaskclient/tor/ClientTransportPlugin.java | 17 ++++++++++++++++- .../se/leap/bitmaskclient/tor/TorServiceCommand.java | 17 ++++++++++++++++- .../se/leap/bitmaskclient/tor/TorServiceConnection.java | 17 ++++++++++++++++- .../se/leap/bitmaskclient/tor/TorStatusObservable.java | 17 ++++++++++++++++- 4 files changed, 64 insertions(+), 4 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java index 5707cde0..764d5f06 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java @@ -1,5 +1,20 @@ package se.leap.bitmaskclient.tor; - +/** + * Copyright (c) 2021 LEAP Encryption Access Project and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ import android.content.Context; import android.os.FileObserver; import android.util.Log; diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java index 1946b861..461ee356 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java @@ -1,5 +1,20 @@ package se.leap.bitmaskclient.tor; - +/** + * Copyright (c) 2021 LEAP Encryption Access Project and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ import android.app.Notification; import android.content.Context; import android.content.Intent; diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java index 0154983a..dbfce2b5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java @@ -1,5 +1,20 @@ package se.leap.bitmaskclient.tor; - +/** + * Copyright (c) 2021 LEAP Encryption Access Project and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index cde17c34..3c280b9c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -1,5 +1,20 @@ package se.leap.bitmaskclient.tor; - +/** + * Copyright (c) 2021 LEAP Encryption Access Project and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ import android.content.Context; import android.util.Log; -- cgit v1.2.3