Verified Commit f20745dc authored by cyberta's avatar cyberta

#8896 skip onboarding for custom branded apps, allow to specify if anonymous...

#8896 skip onboarding for custom branded apps, allow to specify if anonymous usage is preferred over login/signup
parent 52486b79
......@@ -11,10 +11,13 @@ android {
defaultConfig {
applicationId "se.leap.bitmaskclient"
versionCode 134
versionName "0.9.8"
resValue "string", "app_name", appName
vectorDrawables.useSupportLibrary = true
buildConfigField 'boolean', 'openvpn3', 'false'
//Build Config Fields for default donation details
//This is the default donation URL and should be set to the donation page of LEAP
......@@ -28,6 +31,11 @@ android {
buildConfigField 'boolean', 'enable_donation_reminder', 'true'
//The duration in days to trigger the donation reminder
buildConfigField 'int', 'donation_reminder_duration', '30'
//skip the account creation / login screen if the provider offers anonymous vpn usage, use directly the anonymous cert instead
buildConfigField 'boolean', 'priotize_anonymous_usage', 'false'
//ignore the following config, only used in custom flavor
buildConfigField "String", "customProviderUrl", '""'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
dexOptions {
jumboMode true
......@@ -57,21 +65,29 @@ android {
}
//**************************************************************************
//**************************************************************************
//Configurations for custom branded app.
custom {
dimension "branding"
//**************************************************************************
//**************************************************************************
//Configurations for custom branded app.
//Change the package name as needed
applicationId "net.riseup.black"
//Set app name here
appName = "Riseup VPN"
resValue "string", "app_name", appName
//Provider base url, e.g. '"https://example.com"'
def customProviderUrl = '"https://riseup.net"'
buildConfigField "String", "customProviderUrl", customProviderUrl
//Change the versionCode as needed
versionCode 1
//Change the versionName as needed
versionName "1.0"
//skip the account creation / login screen if the provider offers anonymous vpn usage, use directly the anonymous cert instead
buildConfigField 'boolean', 'priotize_anonymous_usage', 'true'
//Build Config Fields for default donation details
//This is the donation URL and should be set to the relevant donation page.
......@@ -82,10 +98,11 @@ android {
buildConfigField 'boolean', 'enable_donation_reminder', 'true'
//The duration in days to trigger the donation reminder
buildConfigField 'int', 'donation_reminder_duration', '30'
}
//**************************************************************************
//**************************************************************************
//**************************************************************************
//**************************************************************************
}
}
buildTypes {
......
......@@ -15,10 +15,8 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="se.leap.bitmaskclient"
android:versionCode="134"
android:versionName="0.9.8" >
package="se.leap.bitmaskclient">
<!-- package is overwritten in build.gradle -->
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="27" />
......@@ -93,6 +91,10 @@
android:name=".ProviderListActivity"
android:label="@string/configuration_wizard_title" />
<activity
android:name=".CustomProviderSetupActivity"
android:label="@string/setup_provider" />
<activity
android:name=".AddProviderActivity"
android:label="@string/add_provider" />
......
......@@ -12,7 +12,6 @@ import android.support.constraint.ConstraintLayout;
import android.support.constraint.Guideline;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.AppCompatTextView;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
......@@ -72,6 +71,8 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity {
protected Provider provider;
protected boolean isCompactLayout = false;
protected boolean isActivityShowing;
private float defaultGuidelineTopPercentage;
private float defaultGuidelineBottomPercentage;
......@@ -79,7 +80,6 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity {
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
provider = getIntent().getParcelableExtra(PROVIDER_KEY);
}
......@@ -135,6 +135,18 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity {
}
}
@Override
protected void onPause() {
super.onPause();
isActivityShowing = false;
}
@Override
protected void onResume() {
super.onResume();
isActivityShowing = true;
}
protected void restoreState(Bundle savedInstanceState) {
if (savedInstanceState != null && savedInstanceState.containsKey(PROVIDER_KEY)) {
provider = savedInstanceState.getParcelable(PROVIDER_KEY);
......
......@@ -30,6 +30,8 @@ public interface Constants {
String APP_ACTION_QUIT = "quit";
String APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE = "configure always-on profile";
String DEFAULT_BITMASK = "normal";
String CUSTOM_BITMASK = "custom";
//////////////////////////////////////////////
......
/**
* Copyright (c) 2018 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 <http://www.gnu.org/licenses/>.
*/
package se.leap.bitmaskclient;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
import static se.leap.bitmaskclient.ProviderAPI.SET_UP_PROVIDER;
import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER;
import static se.leap.bitmaskclient.utils.ConfigHelper.preferAnonymousUsage;
/**
* Created by cyberta on 17.08.18.
*/
public class CustomProviderSetupActivity {
public class CustomProviderSetupActivity extends ProviderSetupBaseActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setUpInitialUI();
restoreState(savedInstanceState);
setProvider(new Provider(BuildConfig.customProviderUrl));
}
@Override
protected void onResume() {
super.onResume();
if (getConfigState() == ProviderConfigState.PROVIDER_NOT_SET) {
showProgressBar();
setupProvider();
}
}
private void setUpInitialUI() {
setContentView(R.layout.a_custom_provider_setup);
setProviderHeaderText(R.string.setup_provider);
hideProgressBar();
}
private void setupProvider() {
setProviderConfigState(SETTING_UP_PROVIDER);
ProviderAPICommand.execute(this, SET_UP_PROVIDER, getProvider());
}
// ------- ProviderSetupInterface ---v
@Override
public void handleProviderSetUp(Provider provider) {
setProvider(provider);
if (provider.allowsAnonymous()) {
downloadVpnCertificate();
} else {
showProviderDetails();
}
}
@Override
public void handleCorrectlyDownloadedCertificate(Provider provider) {
if (preferAnonymousUsage()) {
finishWithSetupWithProvider(provider);
} else {
this.provider = provider;
showProviderDetails();
}
}
// ------- DownloadFailedDialogInterface ---v
@Override
public void retrySetUpProvider(@NonNull Provider provider) {
setupProvider();
showProgressBar();
}
@Override
public void cancelSettingUpProvider() {
super.cancelSettingUpProvider();
finish();
}
@Override
public void addAndSelectNewProvider(String url) {
// ignore
}
private void finishWithSetupWithProvider(Provider provider) {
Intent intent = new Intent();
intent.putExtra(Provider.KEY, provider);
setResult(RESULT_OK, intent);
finish();
}
@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_CONFIGURE_LEAP) {
setResult(resultCode, data);
finish();
}
}
}
......@@ -58,14 +58,17 @@ import se.leap.bitmaskclient.views.VpnStateImage;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK;
import static se.leap.bitmaskclient.Constants.DEFAULT_BITMASK;
import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT;
import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_LOG_IN;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_SWITCH_PROVIDER;
import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
import static se.leap.bitmaskclient.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.ProviderAPI.USER_MESSAGE;
import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message;
import static se.leap.bitmaskclient.utils.ConfigHelper.isDefaultBitmask;
public class EipFragment extends Fragment implements Observer {
......@@ -113,18 +116,30 @@ public class EipFragment extends Fragment implements Observer {
if (arguments != null) {
provider = arguments.getParcelable(PROVIDER_KEY);
if (provider == null) {
activity.startActivityForResult(new Intent(activity, ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER);
handleNoProvider(activity);
} else {
Log.d(TAG, provider.getName() + " configured as provider");
}
} else {
Log.e(TAG, "no provider given - starting ProviderListActivity");
activity.startActivityForResult(new Intent(activity, ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER);
handleNoProvider(activity);
}
}
}
@Override
private void handleNoProvider(Activity activity) {
if (isDefaultBitmask()) {
activity.startActivityForResult(new Intent(activity, ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER);
} else {
Log.e(TAG, "no provider given - try to reconfigure custom provider");
startActivityForResult(new Intent(activity, CustomProviderSetupActivity.class), REQUEST_CODE_CONFIGURE_LEAP);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
openVpnConnection = new EipFragmentServiceConnection();
......
......@@ -190,6 +190,7 @@ public class MainActivity extends AppCompatActivity {
EipCommand.stopVPN(this);
break;
case REQUEST_CODE_CONFIGURE_LEAP:
Log.d(TAG, "REQUEST_CODE_CONFIGURE_LEAP - onActivityResult - MainActivity");
break;
case REQUEST_CODE_LOG_IN:
EipCommand.startVPN(this, true);
......
......@@ -145,6 +145,7 @@ public abstract class ProviderApiManagerBase {
Provider provider = command.getParcelableExtra(PROVIDER_KEY);
if (provider == null) {
//TODO: consider returning error back e.g. NO_PROVIDER
Log.e(TAG, action +" called without provider!");
return;
}
......
package se.leap.bitmaskclient;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.PersistableBundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;
import static se.leap.bitmaskclient.Constants.BROADCAST_PROVIDER_API_EVENT;
import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_SET_UP;
import static se.leap.bitmaskclient.ProviderAPI.UPDATE_PROVIDER_DETAILS;
import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.PENDING_SHOW_FAILED_DIALOG;
import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.PROVIDER_NOT_SET;
import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER;
import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SHOWING_PROVIDER_DETAILS;
import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SHOW_FAILED_DIALOG;
/**
* Created by cyberta on 19.08.18.
*/
public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity implements ProviderAPIResultReceiver.Receiver, ProviderSetupInterface, ProviderSetupFailedDialog.DownloadFailedDialogInterface {
final public static String TAG = "PoviderSetupActivity";
final private static String ACTIVITY_STATE = "ACTIVITY STATE";
final private static String REASON_TO_FAIL = "REASON TO FAIL";
protected ProviderSetupInterface.ProviderConfigState providerConfigState = PROVIDER_NOT_SET;
private ProviderManager providerManager;
private FragmentManagerEnhanced fragmentManager;
private String reasonToFail;
protected boolean testNewURL;
private ProviderApiSetupBroadcastReceiver providerAPIBroadcastReceiver;
private ProviderAPIResultReceiver providerAPIResultReceiver;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragmentManager = new FragmentManagerEnhanced(getSupportFragmentManager());
providerManager = ProviderManager.getInstance(getAssets(), getExternalFilesDir(null));
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "resuming with ConfigState: " + providerConfigState.toString());
setUpProviderAPIResultReceiver();
if (SETTING_UP_PROVIDER == providerConfigState) {
showProgressBar();
checkProviderSetUp();
} else if (PENDING_SHOW_FAILED_DIALOG == providerConfigState) {
showProgressBar();
showDownloadFailedDialog();
} else if (SHOW_FAILED_DIALOG == providerConfigState) {
showProgressBar();
} else if (SHOWING_PROVIDER_DETAILS == providerConfigState) {
cancelSettingUpProvider();
}
}
@Override
protected void onPause() {
super.onPause();
if (providerAPIBroadcastReceiver != null)
LocalBroadcastManager.getInstance(this).unregisterReceiver(providerAPIBroadcastReceiver);
}
@Override
protected void onDestroy() {
super.onDestroy();
providerAPIResultReceiver = null;
}
@Override
public void onSaveInstanceState(@NotNull Bundle outState) {
outState.putString(ACTIVITY_STATE, providerConfigState.toString());
outState.putString(REASON_TO_FAIL, reasonToFail);
super.onSaveInstanceState(outState);
}
protected FragmentManagerEnhanced getFragmentManagerEnhanced() {
return fragmentManager;
}
protected ProviderManager getProviderManager() {
return providerManager;
}
protected void setProviderConfigState(ProviderConfigState state) {
this.providerConfigState = state;
}
protected void setProvider(Provider provider) {
this.provider = provider;
}
// --------- ProviderSetupInterface ---v
@Override
public Provider getProvider() {
return provider;
}
@Override
public ProviderConfigState getConfigState() {
return providerConfigState;
}
@Override
public void handleProviderSetupFailed(Bundle resultData) {
reasonToFail = resultData.getString(ERRORS);
showDownloadFailedDialog();
}
@Override
public void handleIncorrectlyDownloadedCertificate() {
cancelSettingUpProvider();
setResult(RESULT_CANCELED, new Intent(getConfigState().toString()));
}
// -------- DownloadFailedDialogInterface ---v
@Override
public void cancelSettingUpProvider() {
providerConfigState = PROVIDER_NOT_SET;
provider = null;
hideProgressBar();
}
@Override
public void updateProviderDetails() {
providerConfigState = SETTING_UP_PROVIDER;
ProviderAPICommand.execute(this, UPDATE_PROVIDER_DETAILS, provider);
}
// -------- ProviderAPIResultReceiver.Receiver ---v
@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode == ProviderAPI.PROVIDER_OK) {
Provider provider = resultData.getParcelable(PROVIDER_KEY);
handleProviderSetUp(provider);
}
}
protected void restoreState(Bundle savedInstanceState) {
super.restoreState(savedInstanceState);
if (savedInstanceState == null) {
return;
}
this.providerConfigState = ProviderSetupInterface.ProviderConfigState.valueOf(savedInstanceState.getString(ACTIVITY_STATE, PROVIDER_NOT_SET.toString()));
if (savedInstanceState.containsKey(REASON_TO_FAIL)) {
reasonToFail = savedInstanceState.getString(REASON_TO_FAIL);
}
}
private void setUpProviderAPIResultReceiver() {
providerAPIResultReceiver = new ProviderAPIResultReceiver(new Handler(), this);
providerAPIBroadcastReceiver = new ProviderApiSetupBroadcastReceiver(this);
IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_PROVIDER_API_EVENT);
updateIntentFilter.addCategory(Intent.CATEGORY_DEFAULT);
LocalBroadcastManager.getInstance(this).registerReceiver(providerAPIBroadcastReceiver, updateIntentFilter);
}
/**
* Asks ProviderApiService to download an anonymous (anon) VPN certificate.
*/
protected void downloadVpnCertificate() {
ProviderAPICommand.execute(this, DOWNLOAD_VPN_CERTIFICATE, provider);
}
/*
*
*/
public void checkProviderSetUp() {
ProviderAPICommand.execute(this, PROVIDER_SET_UP, provider, providerAPIResultReceiver);
}
/**
* 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.
*/
public void showProviderDetails() {
// show only if current activity is shown
if (isActivityShowing &&
providerConfigState != SHOWING_PROVIDER_DETAILS) {
providerConfigState = SHOWING_PROVIDER_DETAILS;
Intent intent = new Intent(this, ProviderDetailActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.putExtra(PROVIDER_KEY, provider);
startActivityForResult(intent, REQUEST_CODE_CONFIGURE_LEAP);
}
}
/**
* Shows an error dialog, if configuring of a provider failed.
*/
public void showDownloadFailedDialog() {
try {
providerConfigState = SHOW_FAILED_DIALOG;
FragmentTransaction fragmentTransaction = fragmentManager.removePreviousFragment(ProviderSetupFailedDialog.TAG);
DialogFragment newFragment;
try {
JSONObject errorJson = new JSONObject(reasonToFail);
newFragment = ProviderSetupFailedDialog.newInstance(provider, errorJson, testNewURL);
} catch (JSONException e) {
e.printStackTrace();
newFragment = ProviderSetupFailedDialog.newInstance(provider, reasonToFail);
} catch (NullPointerException e) {
//reasonToFail was null
return;
}
newFragment.show(fragmentTransaction, ProviderSetupFailedDialog.TAG);
} catch (IllegalStateException e) {
e.printStackTrace();
providerConfigState = PENDING_SHOW_FAILED_DIALOG;
}
}
}
......@@ -171,8 +171,8 @@ public class ProviderSetupFailedDialog extends DialogFragment {
@Override
public void onCancel(DialogInterface dialog) {
interfaceWithConfigurationWizard.cancelSettingUpProvider();
dialog.dismiss();
interfaceWithConfigurationWizard.cancelSettingUpProvider();
}
@Override
......
......@@ -18,6 +18,7 @@ import se.leap.bitmaskclient.userstatus.User;
import se.leap.bitmaskclient.utils.ConfigHelper;
import static se.leap.bitmaskclient.Constants.APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE;
import static se.leap.bitmaskclient.Constants.DEFAULT_BITMASK;
import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT;
import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION;
import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION;
......@@ -25,6 +26,7 @@ import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
import static se.leap.bitmaskclient.MainActivity.ACTION_SHOW_VPN_FRAGMENT;
import static se.leap.bitmaskclient.utils.ConfigHelper.isDefaultBitmask;
import static se.leap.bitmaskclient.utils.PreferenceHelper.getSavedProviderFromSharedPreferences;
import static se.leap.bitmaskclient.utils.PreferenceHelper.providerInSharedPreferences;
import static se.leap.bitmaskclient.utils.PreferenceHelper.storeProviderInPreferences;
......@@ -181,7 +183,11 @@ public class StartActivity extends Activity{
if (getIntent().hasExtra(APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE)) {
getIntent().removeExtra(APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE);
}
startActivityForResult(new Intent(this, ProviderListActivity.class), REQUEST_CODE_CONFIGURE_LEAP);
if (isDefaultBitmask()) {
startActivityForResult(new Intent(this, ProviderListActivity.class), REQUEST_CODE_CONFIGURE_LEAP);
} else { // custom branded app
startActivityForResult(new Intent(this, CustomProviderSetupActivity.class), REQUEST_CODE_CONFIGURE_LEAP);
}
}
@Override
......
......@@ -73,7 +73,7 @@ public class TLSCompatSocketFactory extends SSLSocketFactory {
trustManager = trustManagers[0];
// Create an SSLContext that uses our TrustManager
// Create a SSLContext that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
internalSSLSocketFactory = sslContext.getSocketFactory();
......
......@@ -50,7 +50,6 @@ import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.ListView;
import se.leap.bitmaskclient.utils.ConfigHelper;
import se.leap.bitmaskclient.DrawerSettingsAdapter;
import se.leap.bitmaskclient.DrawerSettingsAdapter.DrawerSettingsItem;
import se.leap.bitmaskclient.EipFragment;
......@@ -64,11 +63,11 @@ import se.leap.bitmaskclient.fragments.LogFragment;
import static android.content.Context.MODE_PRIVATE;
import static se.leap.bitmaskclient.BitmaskApp.getRefWatcher;
import static se.leap.bitmaskclient.Constants.DONATION_URL;
import static se.leap.bitmaskclient.Constants.ENABLE_DONATION;
import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_SWITCH_PROVIDER;
import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
import static se.leap.bitmaskclient.Constants.DONATION_URL;
import static se.leap.bitmaskclient.Constants.ENABLE_DONATION;
import static se.leap.bitmaskclient.DrawerSettingsAdapter.ABOUT;