summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/androidTest/java/se/leap/bitmaskclient/test/TestGatewaysManager.java54
-rw-r--r--app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java5
-rw-r--r--app/src/main/AndroidManifest.xml2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java8
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Dashboard.java26
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/VpnFragment.java64
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EIP.java2
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java9
-rw-r--r--app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java242
-rw-r--r--app/src/test/resources/gateway_tcp_udp.json1
-rw-r--r--app/src/test/resources/gateway_udp_tcp.json1
-rw-r--r--app/src/test/resources/general_configuration.json1
m---------ics-openvpn0
13 files changed, 382 insertions, 33 deletions
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/TestGatewaysManager.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/TestGatewaysManager.java
index 4817adbb..0a76638f 100644
--- a/app/src/androidTest/java/se/leap/bitmaskclient/test/TestGatewaysManager.java
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/TestGatewaysManager.java
@@ -19,10 +19,12 @@ package se.leap.bitmaskclient.test;
import android.app.*;
import android.content.*;
import android.test.*;
-import android.test.suitebuilder.annotation.*;
import org.json.*;
+import java.io.IOException;
+import java.util.Arrays;
+
import se.leap.bitmaskclient.*;
import se.leap.bitmaskclient.eip.*;
@@ -42,14 +44,13 @@ public class TestGatewaysManager extends InstrumentationTestCase {
@Override
protected void setUp() throws Exception {
+ super.setUp();
context = getInstrumentation().getContext();
assets = new FromAssets(context);
mockGatewaysManager();
mockRealGateway();
- super.setUp();
}
- @MediumTest
public void testFromEipServiceJson() {
gateways_manager.fromEipServiceJson(eip_definition);
assertEquals(2, gateways_manager.size());
@@ -57,13 +58,31 @@ public class TestGatewaysManager extends InstrumentationTestCase {
assertEquals(2, gateways_manager.size());
}
- @SmallTest
+ public void testOrderOfGateways_UDP_TCP() {
+ String[] protocolsInOrder = {"udp", "tcp"};
+ manipulateSupportedProtocols(protocolsInOrder);
+ gateways_manager.fromEipServiceJson(eip_definition);
+ gateways_manager.addFromString(gateway.toString());
+ assertTrue(gateways_manager.select().toString().contains("[\"udp\",\"tcp\"]"));
+ assertFalse(gateways_manager.select().toString().contains("[\"tcp\",\"udp\"]"));
+ }
+
+ public void testOrderOfGateways_TCP_UDP() {
+ String[] protocolsInOrder = {"tcp", "udp"};
+ manipulateSupportedProtocols(protocolsInOrder);
+ gateways_manager.fromEipServiceJson(eip_definition);
+ gateways_manager.addFromString(gateway.toString());
+ assertFalse(gateways_manager.select().toString().contains("[\"udp\",\"tcp\"]"));
+ assertTrue(gateways_manager.select().toString().contains("[\"tcp\",\"udp\"]"));
+ }
+
public void testAddFromString() {
gateways_manager.addFromString("");
+ assertEquals(0, gateways_manager.size());
gateways_manager.addFromString(gateway.toString());
+ assertEquals(1, gateways_manager.size());
}
- @MediumTest
public void testRemoveDuplicate() {
gateways_manager.addFromString(gateway.toString());
assertEquals(1, gateways_manager.size());
@@ -73,7 +92,6 @@ public class TestGatewaysManager extends InstrumentationTestCase {
assertEquals(1, gateways_manager.size());
}
- @MediumTest
public void testToString() {
assertEquals("[]", gateways_manager.toString());
@@ -81,7 +99,6 @@ public class TestGatewaysManager extends InstrumentationTestCase {
assertEquals("[" + gateway.toString() + "]", gateways_manager.toString());
}
- @SmallTest
public void testIsEmpty() {
assertTrue(gateways_manager.isEmpty());
gateways_manager.addFromString("");
@@ -107,6 +124,29 @@ public class TestGatewaysManager extends InstrumentationTestCase {
}
}
+ private void manipulateSupportedProtocols(String[] protocols) {
+ try {
+ eip_definition = new JSONObject(assets.toString(TestConstants.EIP_DEFINITION_FILE));
+ JSONObject secrets = new JSONObject(assets.toString(TestConstants.SECRETS_FILE));
+ JSONArray protocolJsonArray = new JSONArray(Arrays.asList(protocols));
+ JSONArray gateways = eip_definition.getJSONArray("gateways");
+ for (int i = 0; i < gateways.length(); i++) {
+ JSONObject gatewayJson = gateways.getJSONObject(i);
+ JSONObject capabilitiesJson = gatewayJson.getJSONObject("capabilities");
+ capabilitiesJson.put("protocols", protocolJsonArray);
+ gatewayJson.put("protocols", protocolJsonArray);
+ }
+ this.gateway = new Gateway(eip_definition, secrets, gateways.getJSONObject(0));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ assertFalse(true);
+ } catch (IOException e) {
+ e.printStackTrace();
+ assertFalse(true);
+ }
+
+ }
+
private void mockArtificialGateway() {
try {
eip_definition = new JSONObject(assets.toString(TestConstants.EIP_DEFINITION_FILE));
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java
index d339ab26..93b1da47 100644
--- a/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java
@@ -33,7 +33,7 @@ public class VpnTestController {
Button button = getVpnButton();
if(!isVpnButton(button))
throw new IllegalStateException();
- solo.clickOnView(button);
+ solo.clickOnButton(String.valueOf(button.getText()));
}
protected Button getVpnButton() {
@@ -93,8 +93,6 @@ public class VpnTestController {
protected void turningEipOff() {
okToBrowserWarning();
- sayOkToDisconnect();
-
int max_seconds_until_connected = 120;
Condition condition = new Condition() {
@@ -123,6 +121,7 @@ public class VpnTestController {
solo.clickOnButton(disconnect);
}
+ @SuppressWarnings("unused")
private void sayOkToDisconnect() throws IllegalStateException {
boolean disconnect_vpn_appeared = solo.waitForActivity(DisconnectVPN.class);
if(disconnect_vpn_appeared){
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 025c98f0..67fd0a1a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -85,7 +85,7 @@
android:name="se.leap.bitmaskclient.Dashboard"
android:label="@string/title_activity_dashboard"
android:uiOptions="splitActionBarWhenNarrow"
- android:launchMode="singleTask"
+ android:launchMode="singleTop"
>
<intent-filter android:label="@string/app_name">
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
index 5faa1de4..835e69b3 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
@@ -322,9 +322,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
- Intent disconnectVPN = new Intent(this, DisconnectVPN.class);
- disconnectVPN.setAction(DISCONNECT_VPN);
- PendingIntent disconnectPendingIntent = PendingIntent.getActivity(this, 0, disconnectVPN, 0);
+ Intent disconnectVPN = new Intent(this, Dashboard.class);
+ disconnectVPN.putExtra(Dashboard.ACTION_ASK_TO_CANCEL_VPN, true);
+ disconnectVPN.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ PendingIntent disconnectPendingIntent = PendingIntent.getActivity(this, 0, disconnectVPN, PendingIntent.FLAG_CANCEL_CURRENT);
nbuilder.addAction(R.drawable.ic_menu_close_clear_cancel,
getString(R.string.cancel_connection), disconnectPendingIntent);
diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
index dbdf0a51..a6a3717b 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
@@ -66,9 +66,11 @@ public class Dashboard extends Activity implements ProviderAPIResultReceiver.Rec
public static final String TAG = Dashboard.class.getSimpleName();
public static final String SHARED_PREFERENCES = "LEAPPreferences";
public static final String ACTION_QUIT = "quit";
+ public static final String ACTION_ASK_TO_CANCEL_VPN = "ask to cancel vpn";
public static final String REQUEST_CODE = "request_code";
public static final String PARAMETERS = "dashboard parameters";
public static final String START_ON_BOOT = "dashboard start on boot";
+ //FIXME: remove OR FIX ON_BOOT
public static final String ON_BOOT = "dashboard on boot";
public static final String APP_VERSION = "bitmask version";
@@ -116,6 +118,12 @@ public class Dashboard extends Activity implements ProviderAPIResultReceiver.Rec
}
}
+ @Override
+ protected void onResume() {
+ super.onResume();
+ handleVPNCancellation(getIntent());
+ }
+
private boolean previousProviderExists(Bundle savedInstanceState) {
return providerInSavedInstance(savedInstanceState) || providerInSharedPreferences();
}
@@ -176,6 +184,13 @@ public class Dashboard extends Activity implements ProviderAPIResultReceiver.Rec
}
@Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ handleVPNCancellation(intent);
+ }
+
+ @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CONFIGURE_LEAP || requestCode == SWITCH_PROVIDER) {
if (resultCode == RESULT_OK && data.hasExtra(Provider.KEY)) {
@@ -192,8 +207,13 @@ public class Dashboard extends Activity implements ProviderAPIResultReceiver.Rec
finish();
} else
configErrorDialog();
- } else if (requestCode == EIP.DISCONNECT) {
- EipStatus.getInstance().setConnectedOrDisconnected();
+ }
+ }
+
+ private void handleVPNCancellation(Intent intent) {
+ if (intent.hasExtra(Dashboard.ACTION_ASK_TO_CANCEL_VPN)) {
+ eip_fragment.askToStopEIP();
+ intent.removeExtra(ACTION_ASK_TO_CANCEL_VPN);
}
}
@@ -247,7 +267,9 @@ public class Dashboard extends Activity implements ProviderAPIResultReceiver.Rec
eip_fragment = new VpnFragment();
if (hide_and_turn_on_eip) {
+ //TODO: remove line below if not in use anymore...
preferences.edit().remove(Dashboard.START_ON_BOOT).apply();
+ //FIXME: always start on Boot? Why do we keep shared preferences then?
Bundle arguments = new Bundle();
arguments.putBoolean(VpnFragment.START_ON_BOOT, true);
if (eip_fragment != null) eip_fragment.setArguments(arguments);
diff --git a/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java b/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java
index 9e9adef1..8cd9fa0f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java
@@ -19,7 +19,6 @@ package se.leap.bitmaskclient;
import android.app.*;
import android.content.*;
import android.os.*;
-import android.util.Log;
import android.view.*;
import android.widget.*;
@@ -28,7 +27,10 @@ import org.jetbrains.annotations.*;
import java.util.*;
import butterknife.*;
-import de.blinkt.openvpn.activities.*;
+import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
+import de.blinkt.openvpn.core.OpenVPNService;
+import de.blinkt.openvpn.core.ProfileManager;
+import de.blinkt.openvpn.core.VpnStatus;
import mbanje.kurt.fabbutton.*;
import se.leap.bitmaskclient.eip.*;
@@ -50,15 +52,31 @@ public class VpnFragment extends Fragment implements Observer {
private static EipStatus eip_status;
private boolean wants_to_connect;
+ private IOpenVPNServiceInternal mService;
+ private ServiceConnection openVpnConnection = new ServiceConnection() {
+
+
+
+ @Override
+ public void onServiceConnected(ComponentName className,
+ IBinder service) {
+
+ mService = IOpenVPNServiceInternal.Stub.asInterface(service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName arg0) {
+ mService = null;
+ }
+
+ };
+
//FIXME: replace with onAttach(Context context)
public void onAttach(Activity activity) {
super.onAttach(activity);
dashboard = (Dashboard) activity;
- ProviderAPIResultReceiver provider_api_receiver = new ProviderAPIResultReceiver(new Handler(), dashboard);
-
- if(eip_receiver != null)
- ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.DOWNLOAD_EIP_SERVICE, provider_api_receiver);
+ downloadEIPServiceConfig();
}
@Override
@@ -95,6 +113,13 @@ public class VpnFragment extends Fragment implements Observer {
//FIXME: avoid race conditions while checking certificate an logging in at about the same time
//eipCommand(Constants.ACTION_CHECK_CERT_VALIDITY);
handleNewState(eip_status);
+ bindOpenVpnService();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ dashboard.unbindService(openVpnConnection);
}
@Override
@@ -104,7 +129,7 @@ public class VpnFragment extends Fragment implements Observer {
super.onSaveInstanceState(outState);
}
- protected void saveStatus() {
+ private void saveStatus() {
boolean is_on = eip_status.isConnected() || eip_status.isConnecting();
Dashboard.preferences.edit().putBoolean(Dashboard.START_ON_BOOT, is_on).commit();
}
@@ -184,16 +209,29 @@ public class VpnFragment extends Fragment implements Observer {
}
private void disconnect() {
- Intent disconnect_vpn = new Intent(dashboard, DisconnectVPN.class);
- dashboard.startActivityForResult(disconnect_vpn, EIP.DISCONNECT);
eip_status.setDisconnecting();
+ ProfileManager.setConntectedVpnProfileDisconnected(dashboard);
+ if (mService != null) {
+ try {
+ mService.stopVPN(false);
+ eip_status.setConnectedOrDisconnected();
+ } catch (RemoteException e) {
+ VpnStatus.logException(e);
+ }
+ }
}
protected void stopEipIfPossible() {
eipCommand(Constants.ACTION_STOP_EIP);
}
- private void askToStopEIP() {
+ private void downloadEIPServiceConfig() {
+ ProviderAPIResultReceiver provider_api_receiver = new ProviderAPIResultReceiver(new Handler(), dashboard);
+ if(eip_receiver != null)
+ ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.DOWNLOAD_EIP_SERVICE, provider_api_receiver);
+ }
+
+ protected void askToStopEIP() {
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(dashboard);
alertBuilder.setTitle(dashboard.getString(R.string.eip_cancel_connect_title))
.setMessage(dashboard.getString(R.string.eip_warning_browser_inconsistency))
@@ -282,6 +320,12 @@ public class VpnFragment extends Fragment implements Observer {
}
}
+ private void bindOpenVpnService() {
+ Intent intent = new Intent(dashboard, OpenVPNService.class);
+ intent.setAction(OpenVPNService.START_SERVICE);
+ dashboard.bindService(intent, openVpnConnection, Context.BIND_AUTO_CREATE);
+ }
+
protected class EIPReceiver extends ResultReceiver {
protected EIPReceiver(Handler handler) {
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 eb83814a..73c7337b 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
@@ -42,8 +42,6 @@ public final class EIP extends IntentService {
public final static String TAG = EIP.class.getSimpleName();
public final static String SERVICE_API_PATH = "config/eip-service.json";
- public static final int DISCONNECT = 15;
-
private static Context context;
private static ResultReceiver mReceiver;
private static SharedPreferences preferences;
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
index 10a95dfb..53d81ed3 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
@@ -79,7 +79,6 @@ public class VpnConfigGenerator {
String ports_keyword = "ports";
String protocol_keyword = "protocols";
String capabilities_keyword = "capabilities";
- String udp = "udp";
try {
String ip_address = gateway.getString(ip_address_keyword);
@@ -93,9 +92,7 @@ public class VpnConfigGenerator {
String protocol = protocols.optString(j);
String new_remote = remote_keyword + " " + ip_address + " " + port + " " + protocol + new_line;
- port_specific_remotes = protocol.equalsIgnoreCase(udp) ?
- port_specific_remotes.replaceFirst(remote_keyword, new_remote + new_line + remote_keyword) :
- new_remote;
+ port_specific_remotes += new_remote;
}
remotes += port_specific_remotes;
}
@@ -103,7 +100,9 @@ public class VpnConfigGenerator {
// TODO Auto-generated catch block
e.printStackTrace();
}
-
+ if (remotes.endsWith(new_line)) {
+ remotes = remotes.substring(0, remotes.lastIndexOf(new_line));
+ }
return remotes;
}
diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java
new file mode 100644
index 00000000..7e60edb9
--- /dev/null
+++ b/app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java
@@ -0,0 +1,242 @@
+package se.leap.bitmaskclient.eip;
+
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+
+import se.leap.bitmaskclient.TestUtils;
+
+import static junit.framework.Assert.assertTrue;
+
+/**
+ * Created by cyberta on 03.10.17.
+ */
+public class VpnConfigGeneratorTest {
+
+ private VpnConfigGenerator vpnConfigGenerator;
+ private JSONObject generalConfig;
+ private JSONObject gateway;
+ private JSONObject secrets;
+
+ String expectedVPNConfig_tcp_udp = "cipher AES-128-CBC \n" +
+ "auth SHA1 \n" +
+ "tun-ipv6 true \n" +
+ "keepalive 10 30 \n" +
+ "tls-cipher DHE-RSA-AES128-SHA \n" +
+ "client\n" +
+ "remote 198.252.153.84 443 tcp\n" +
+ "remote 198.252.153.84 443 udp\n" +
+ "<ca>\n" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIFbzCCA1egAwIBAgIBATANBgkqhkiG9w0BAQ0FADBKMRgwFgYDVQQDDA9CaXRt\n" +
+ "YXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNVBAsME2h0dHBzOi8v\n" +
+ "Yml0bWFzay5uZXQwHhcNMTIxMTA2MDAwMDAwWhcNMjIxMTA2MDAwMDAwWjBKMRgw\n" +
+ "FgYDVQQDDA9CaXRtYXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNV\n" +
+ "BAsME2h0dHBzOi8vYml0bWFzay5uZXQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n" +
+ "ggIKAoICAQC1eV4YvayaU+maJbWrD4OHo3d7S1BtDlcvkIRS1Fw3iYDjsyDkZxai\n" +
+ "dHp4EUasfNQ+EVtXUvtk6170EmLco6Elg8SJBQ27trE6nielPRPCfX3fQzETRfvB\n" +
+ "7tNvGw4Jn2YKiYoMD79kkjgyZjkJ2r/bEHUSevmR09BRp86syHZerdNGpXYhcQ84\n" +
+ "CA1+V+603GFIHnrP+uQDdssW93rgDNYu+exT+Wj6STfnUkugyjmPRPjL7wh0tzy+\n" +
+ "znCeLl4xiV3g9sjPnc7r2EQKd5uaTe3j71sDPF92KRk0SSUndREz+B1+Dbe/RGk4\n" +
+ "MEqGFuOzrtsgEhPIX0hplhb0Tgz/rtug+yTT7oJjBa3u20AAOQ38/M99EfdeJvc4\n" +
+ "lPFF1XBBLh6X9UKF72an2NuANiX6XPySnJgZ7nZ09RiYZqVwu/qt3DfvLfhboq+0\n" +
+ "bQvLUPXrVDr70onv5UDjpmEA/cLmaIqqrduuTkFZOym65/PfAPvpGnt7crQj/Ibl\n" +
+ "DEDYZQmP7AS+6zBjoOzNjUGE5r40zWAR1RSi7zliXTu+yfsjXUIhUAWmYR6J3KxB\n" +
+ "lfsiHBQ+8dn9kC3YrUexWoOqBiqJOAJzZh5Y1tqgzfh+2nmHSB2dsQRs7rDRRlyy\n" +
+ "YMbkpzL9ZsOUO2eTP1mmar6YjCN+rggYjRrX71K2SpBG6b1zZxOG+wIDAQABo2Aw\n" +
+ "XjAdBgNVHQ4EFgQUuYGDLL2sswnYpHHvProt1JU+D48wDgYDVR0PAQH/BAQDAgIE\n" +
+ "MAwGA1UdEwQFMAMBAf8wHwYDVR0jBBgwFoAUuYGDLL2sswnYpHHvProt1JU+D48w\n" +
+ "DQYJKoZIhvcNAQENBQADggIBADeG67vaFcbITGpi51264kHPYPEWaXUa5XYbtmBl\n" +
+ "cXYyB6hY5hv/YNuVGJ1gWsDmdeXEyj0j2icGQjYdHRfwhrbEri+h1EZOm1cSBDuY\n" +
+ "k/P5+ctHyOXx8IE79DBsZ6IL61UKIaKhqZBfLGYcWu17DVV6+LT+AKtHhOrv3TSj\n" +
+ "RnAcKnCbKqXLhUPXpK0eTjPYS2zQGQGIhIy9sQXVXJJJsGrPgMxna1Xw2JikBOCG\n" +
+ "htD/JKwt6xBmNwktH0GI/LVtVgSp82Clbn9C4eZN9E5YbVYjLkIEDhpByeC71QhX\n" +
+ "EIQ0ZR56bFuJA/CwValBqV/G9gscTPQqd+iETp8yrFpAVHOW+YzSFbxjTEkBte1J\n" +
+ "aF0vmbqdMAWLk+LEFPQRptZh0B88igtx6tV5oVd+p5IVRM49poLhuPNJGPvMj99l\n" +
+ "mlZ4+AeRUnbOOeAEuvpLJbel4rhwFzmUiGoeTVoPZyMevWcVFq6BMkS+jRR2w0jK\n" +
+ "G6b0v5XDHlcFYPOgUrtsOBFJVwbutLvxdk6q37kIFnWCd8L3kmES5q4wjyFK47Co\n" +
+ "Ja8zlx64jmMZPg/t3wWqkZgXZ14qnbyG5/lGsj5CwVtfDljrhN0oCWK1FZaUmW3d\n" +
+ "69db12/g4f6phldhxiWuGC/W6fCW5kre7nmhshcltqAJJuU47iX+DarBFiIj816e\n" +
+ "yV8e\n" +
+ "-----END CERTIFICATE-----\n" +
+ "\n" +
+ "</ca>\n" +
+ "<key>\n" +
+ "-----BEGIN RSA PRIVATE KEY-----\n" +
+ "MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDUTYWeGgsHS+fjijmziniNqw6h\n" +
+ "MBpyK4S/cM6PxV28C33VuOWPTMcIYesctjZANWFCggfFTQSjV5Qaxq9UK4i27tayLbCdlVS6hpbl\n" +
+ "Vf4DuI3Gj1Pv1rtITBShtvCf3T7yBnjW4wVpOpsUAAOViKUSvUU3kPPMFWhiGQw8yHYr82ts6XMo\n" +
+ "jwMoonW5Ml4e7C7Cr22QesC63q7emNcpUd0pZGT9C33RgDAHZDMrlyjo4HEp1JbUfB0gbmXElJbE\n" +
+ "1TNdZ62HhgmMjzTUN1GGrQ1t91AEoEQwaK65o4YSj+yFv6KXZZz5OWaz94tKiN9v26EXtBFmRlyb\n" +
+ "6+D9ynSd9LghAgMBAAECggEBANPHLRXkhsHVj1EkzqBx7gXr8CEMmiTvknFh9zvltrZhhDoRQjWr\n" +
+ "chPDkcRHY2Cznvy4N0YyqQDD2ULIlZdSAgPxxothFoBruWSD47yMBmLx08ORsDpcqt/YvPAATJI8\n" +
+ "IpFNsXcyaXBp/M57oRemgnxp/8UJPJmFdWX99H4hvffh/jdj7POgYiWUaAl37XTYZKZ4nzKU2wpL\n" +
+ "EDLj9RKPz9gG7CYp2zrLC9LaAsrXVrKwPBw6g+XwbClaqFj97db3mrY4lr6mTo89qmus1AU+fBDH\n" +
+ "3Xlpmc8JwB+30TvhRNKrpLx9cEjuEj7K1gm8Y4dWCjPi+lNbtAyUBcgPJFa/81ECgYEA7pLoBU/Y\n" +
+ "ZYjyHFca8FvDBcBh6haHfqJr9doXWtgjDrbi3o2n5wHqfKhFWOH6vPEQozkOVeX1ze6HOiRmGBpW\n" +
+ "r+r7x8TD25L7I6HJw3M351RWOAfkF0w/RTVdetcTgduQtfN1u6BDhYSVceXMjyQYx7MhfETWI8Gh\n" +
+ "KSYm8OEDYiUCgYEA489fmbrCcUnXzpTsbswJ5NmSoEXbcX8cLxnQuzE0z9GHhQdrMjOpXR76reTW\n" +
+ "6jcuudarNcwRUYSWWhjCDKHhpx4HhasWPaHgr7jIzcRw8yZSJRSxKr8sl1qh6g7s47JcmfXOMWLt\n" +
+ "yuyE933XrT19Th4ODZHY40Uv35mPjMi9d00CgYEAyRNAQtndBRa7GG/B4Ls2T+6pl+aNJIo4e+no\n" +
+ "rURlp800wWabEPRocdBRQmyULBLxduBr2LIMzhgwGSz8b2wji/l9ZA3PFY135bxClVzSzUIjuO3N\n" +
+ "rGUzHl2wAAyuAFDSUshzfkPBJRNt8aVBF5PQ3t93ZYmPAmv8LPZe875yX5ECgYEAsUEcwK/ZNW7g\n" +
+ "dQPZR4iJNkC4Xu6cBZ6Cnn92swBheEYvLSoNlX0vDZ7aLE3/jzQqrjzC8NP8sbH5jtbuvgeDXZX3\n" +
+ "AmGRp5j6C6A61ihAPmEVz3ZfN8SSfJ3vl//PAIg6lyz0J+cy4Q7RkwSeuVQ72Hl4M8TEvmmKC3Af\n" +
+ "ispy6Y0CgYEAgl1o2lo+ACyk+oVQPaaPqK3d7WOBFp4eR2nXFor/vsx9igQOlZUgzRDQsR8jo1o9\n" +
+ "efOSBf87igrZGgssys89pWa2dnXnz5PMmzkKr6bw4D9Ez6u6Puc9UZhGw/8wDYg6fSosdB9utspm\n" +
+ "M698ycef7jBNMDgmhpSvfw5GctoNQ4s=\n" +
+ "-----END RSA PRIVATE KEY-----\n" +
+ "</key>\n" +
+ "<cert>\n" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIEjDCCAnSgAwIBAgIQG6MBp/cd9DlY+7cdvp3R3jANBgkqhkiG9w0BAQsFADBmMRAwDgYDVQQK\n" +
+ "DAdCaXRtYXNrMRwwGgYDVQQLDBNodHRwczovL2JpdG1hc2submV0MTQwMgYDVQQDDCtCaXRtYXNr\n" +
+ "IFJvb3QgQ0EgKGNsaWVudCBjZXJ0aWZpY2F0ZXMgb25seSEpMB4XDTE0MTIwNTAwMDAwMFoXDTE1\n" +
+ "MDMwNTAwMDAwMFowLTErMCkGA1UEAwwiVU5MSU1JVEVEZDBwZDdkMzE4eTNtOHNkeXllaTFqYmZl\n" +
+ "eDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANRNhZ4aCwdL5+OKObOKeI2rDqEwGnIr\n" +
+ "hL9wzo/FXbwLfdW45Y9Mxwhh6xy2NkA1YUKCB8VNBKNXlBrGr1QriLbu1rItsJ2VVLqGluVV/gO4\n" +
+ "jcaPU+/Wu0hMFKG28J/dPvIGeNbjBWk6mxQAA5WIpRK9RTeQ88wVaGIZDDzIdivza2zpcyiPAyii\n" +
+ "dbkyXh7sLsKvbZB6wLrert6Y1ylR3SlkZP0LfdGAMAdkMyuXKOjgcSnUltR8HSBuZcSUlsTVM11n\n" +
+ "rYeGCYyPNNQ3UYatDW33UASgRDBorrmjhhKP7IW/opdlnPk5ZrP3i0qI32/boRe0EWZGXJvr4P3K\n" +
+ "dJ30uCECAwEAAaNvMG0wHQYDVR0OBBYEFK8bMVAM4GBB5sHptoIOAaIvlYueMAsGA1UdDwQEAwIH\n" +
+ "gDATBgNVHSUEDDAKBggrBgEFBQcDAjAJBgNVHRMEAjAAMB8GA1UdIwQYMBaAFId+E7bsWFsUWah9\n" +
+ "vZuPvZ7O+aJsMA0GCSqGSIb3DQEBCwUAA4ICAQAQOX81csVhvP422NKkZH7+g3npBpl+sEHedaGR\n" +
+ "xYPOu4HrA4TVF9h44sljRoRJyenGNdBZCXcLKHg889eePTf8Z5K3lTojp6hvwyA6tgxOMHT1kESW\n" +
+ "PfqnRw8mHfHJuE3g+4YNUMwggzwc/VZATdV/7M33sarVN9AUOHou9n9BizgCC+UnYlS+F2POumE3\n" +
+ "FbOhKo5uubI02MwBYlN2JVO2TBt1Q20w8wc6cU07Xi5Epp+1mkgFiOShkNtPcJmEyBWJhxDtSDOW\n" +
+ "2doqWYNqH2kq7B5R/kyyfcpFJqAnBTV7xs+C5rTS1mW7LpxfdCUMbYuLCpyxpO3A/DhAm8n47tUH\n" +
+ "lBtmo8Avdb8VdFpYiGBpB0o9kTFcsWFb2GkWFBduGfSEB8jUI7QtqhgZqocAKK/cweSRV8FwyUcn\n" +
+ "R0prRm3QEi9fbXqEddzjSY9y/lqWYzT7u+IOAQpKroeZ4wzgYperDNOUFuYk1rP7yuvjP2pV5rcN\n" +
+ "yPoBP60TPVWMRM4WJm6nTogAz2qBrFsf/XwT/ajzbsjT6HNB7QbRE+wkFkqspoXG5Agp7KQ8lW3L\n" +
+ "SKCDGOQJz7VIE85pD0tg7QEXBEw8oaRZtMjQ0Gvs25mxXAKka4wGasaWfYH6d0E+iKYcWn86V1rH\n" +
+ "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" +
+ "-----END CERTIFICATE-----\n" +
+ "</cert>\n" +
+ "remote-cert-tls server\n" +
+ "persist-tun\n" +
+ "auth-retry nointeract";
+
+ String expectedVPNConfig_udp_tcp = "cipher AES-128-CBC \n" +
+ "auth SHA1 \n" +
+ "tun-ipv6 true \n" +
+ "keepalive 10 30 \n" +
+ "tls-cipher DHE-RSA-AES128-SHA \n" +
+ "client\n" +
+ "remote 198.252.153.84 443 udp\n" +
+ "remote 198.252.153.84 443 tcp\n" +
+ "<ca>\n" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIFbzCCA1egAwIBAgIBATANBgkqhkiG9w0BAQ0FADBKMRgwFgYDVQQDDA9CaXRt\n" +
+ "YXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNVBAsME2h0dHBzOi8v\n" +
+ "Yml0bWFzay5uZXQwHhcNMTIxMTA2MDAwMDAwWhcNMjIxMTA2MDAwMDAwWjBKMRgw\n" +
+ "FgYDVQQDDA9CaXRtYXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNV\n" +
+ "BAsME2h0dHBzOi8vYml0bWFzay5uZXQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n" +
+ "ggIKAoICAQC1eV4YvayaU+maJbWrD4OHo3d7S1BtDlcvkIRS1Fw3iYDjsyDkZxai\n" +
+ "dHp4EUasfNQ+EVtXUvtk6170EmLco6Elg8SJBQ27trE6nielPRPCfX3fQzETRfvB\n" +
+ "7tNvGw4Jn2YKiYoMD79kkjgyZjkJ2r/bEHUSevmR09BRp86syHZerdNGpXYhcQ84\n" +
+ "CA1+V+603GFIHnrP+uQDdssW93rgDNYu+exT+Wj6STfnUkugyjmPRPjL7wh0tzy+\n" +
+ "znCeLl4xiV3g9sjPnc7r2EQKd5uaTe3j71sDPF92KRk0SSUndREz+B1+Dbe/RGk4\n" +
+ "MEqGFuOzrtsgEhPIX0hplhb0Tgz/rtug+yTT7oJjBa3u20AAOQ38/M99EfdeJvc4\n" +
+ "lPFF1XBBLh6X9UKF72an2NuANiX6XPySnJgZ7nZ09RiYZqVwu/qt3DfvLfhboq+0\n" +
+ "bQvLUPXrVDr70onv5UDjpmEA/cLmaIqqrduuTkFZOym65/PfAPvpGnt7crQj/Ibl\n" +
+ "DEDYZQmP7AS+6zBjoOzNjUGE5r40zWAR1RSi7zliXTu+yfsjXUIhUAWmYR6J3KxB\n" +
+ "lfsiHBQ+8dn9kC3YrUexWoOqBiqJOAJzZh5Y1tqgzfh+2nmHSB2dsQRs7rDRRlyy\n" +
+ "YMbkpzL9ZsOUO2eTP1mmar6YjCN+rggYjRrX71K2SpBG6b1zZxOG+wIDAQABo2Aw\n" +
+ "XjAdBgNVHQ4EFgQUuYGDLL2sswnYpHHvProt1JU+D48wDgYDVR0PAQH/BAQDAgIE\n" +
+ "MAwGA1UdEwQFMAMBAf8wHwYDVR0jBBgwFoAUuYGDLL2sswnYpHHvProt1JU+D48w\n" +
+ "DQYJKoZIhvcNAQENBQADggIBADeG67vaFcbITGpi51264kHPYPEWaXUa5XYbtmBl\n" +
+ "cXYyB6hY5hv/YNuVGJ1gWsDmdeXEyj0j2icGQjYdHRfwhrbEri+h1EZOm1cSBDuY\n" +
+ "k/P5+ctHyOXx8IE79DBsZ6IL61UKIaKhqZBfLGYcWu17DVV6+LT+AKtHhOrv3TSj\n" +
+ "RnAcKnCbKqXLhUPXpK0eTjPYS2zQGQGIhIy9sQXVXJJJsGrPgMxna1Xw2JikBOCG\n" +
+ "htD/JKwt6xBmNwktH0GI/LVtVgSp82Clbn9C4eZN9E5YbVYjLkIEDhpByeC71QhX\n" +
+ "EIQ0ZR56bFuJA/CwValBqV/G9gscTPQqd+iETp8yrFpAVHOW+YzSFbxjTEkBte1J\n" +
+ "aF0vmbqdMAWLk+LEFPQRptZh0B88igtx6tV5oVd+p5IVRM49poLhuPNJGPvMj99l\n" +
+ "mlZ4+AeRUnbOOeAEuvpLJbel4rhwFzmUiGoeTVoPZyMevWcVFq6BMkS+jRR2w0jK\n" +
+ "G6b0v5XDHlcFYPOgUrtsOBFJVwbutLvxdk6q37kIFnWCd8L3kmES5q4wjyFK47Co\n" +
+ "Ja8zlx64jmMZPg/t3wWqkZgXZ14qnbyG5/lGsj5CwVtfDljrhN0oCWK1FZaUmW3d\n" +
+ "69db12/g4f6phldhxiWuGC/W6fCW5kre7nmhshcltqAJJuU47iX+DarBFiIj816e\n" +
+ "yV8e\n" +
+ "-----END CERTIFICATE-----\n" +
+ "\n" +
+ "</ca>\n" +
+ "<key>\n" +
+ "-----BEGIN RSA PRIVATE KEY-----\n" +
+ "MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDUTYWeGgsHS+fjijmziniNqw6h\n" +
+ "MBpyK4S/cM6PxV28C33VuOWPTMcIYesctjZANWFCggfFTQSjV5Qaxq9UK4i27tayLbCdlVS6hpbl\n" +
+ "Vf4DuI3Gj1Pv1rtITBShtvCf3T7yBnjW4wVpOpsUAAOViKUSvUU3kPPMFWhiGQw8yHYr82ts6XMo\n" +
+ "jwMoonW5Ml4e7C7Cr22QesC63q7emNcpUd0pZGT9C33RgDAHZDMrlyjo4HEp1JbUfB0gbmXElJbE\n" +
+ "1TNdZ62HhgmMjzTUN1GGrQ1t91AEoEQwaK65o4YSj+yFv6KXZZz5OWaz94tKiN9v26EXtBFmRlyb\n" +
+ "6+D9ynSd9LghAgMBAAECggEBANPHLRXkhsHVj1EkzqBx7gXr8CEMmiTvknFh9zvltrZhhDoRQjWr\n" +
+ "chPDkcRHY2Cznvy4N0YyqQDD2ULIlZdSAgPxxothFoBruWSD47yMBmLx08ORsDpcqt/YvPAATJI8\n" +
+ "IpFNsXcyaXBp/M57oRemgnxp/8UJPJmFdWX99H4hvffh/jdj7POgYiWUaAl37XTYZKZ4nzKU2wpL\n" +
+ "EDLj9RKPz9gG7CYp2zrLC9LaAsrXVrKwPBw6g+XwbClaqFj97db3mrY4lr6mTo89qmus1AU+fBDH\n" +
+ "3Xlpmc8JwB+30TvhRNKrpLx9cEjuEj7K1gm8Y4dWCjPi+lNbtAyUBcgPJFa/81ECgYEA7pLoBU/Y\n" +
+ "ZYjyHFca8FvDBcBh6haHfqJr9doXWtgjDrbi3o2n5wHqfKhFWOH6vPEQozkOVeX1ze6HOiRmGBpW\n" +
+ "r+r7x8TD25L7I6HJw3M351RWOAfkF0w/RTVdetcTgduQtfN1u6BDhYSVceXMjyQYx7MhfETWI8Gh\n" +
+ "KSYm8OEDYiUCgYEA489fmbrCcUnXzpTsbswJ5NmSoEXbcX8cLxnQuzE0z9GHhQdrMjOpXR76reTW\n" +
+ "6jcuudarNcwRUYSWWhjCDKHhpx4HhasWPaHgr7jIzcRw8yZSJRSxKr8sl1qh6g7s47JcmfXOMWLt\n" +
+ "yuyE933XrT19Th4ODZHY40Uv35mPjMi9d00CgYEAyRNAQtndBRa7GG/B4Ls2T+6pl+aNJIo4e+no\n" +
+ "rURlp800wWabEPRocdBRQmyULBLxduBr2LIMzhgwGSz8b2wji/l9ZA3PFY135bxClVzSzUIjuO3N\n" +
+ "rGUzHl2wAAyuAFDSUshzfkPBJRNt8aVBF5PQ3t93ZYmPAmv8LPZe875yX5ECgYEAsUEcwK/ZNW7g\n" +
+ "dQPZR4iJNkC4Xu6cBZ6Cnn92swBheEYvLSoNlX0vDZ7aLE3/jzQqrjzC8NP8sbH5jtbuvgeDXZX3\n" +
+ "AmGRp5j6C6A61ihAPmEVz3ZfN8SSfJ3vl//PAIg6lyz0J+cy4Q7RkwSeuVQ72Hl4M8TEvmmKC3Af\n" +
+ "ispy6Y0CgYEAgl1o2lo+ACyk+oVQPaaPqK3d7WOBFp4eR2nXFor/vsx9igQOlZUgzRDQsR8jo1o9\n" +
+ "efOSBf87igrZGgssys89pWa2dnXnz5PMmzkKr6bw4D9Ez6u6Puc9UZhGw/8wDYg6fSosdB9utspm\n" +
+ "M698ycef7jBNMDgmhpSvfw5GctoNQ4s=\n" +
+ "-----END RSA PRIVATE KEY-----\n" +
+ "</key>\n" +
+ "<cert>\n" +
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIEjDCCAnSgAwIBAgIQG6MBp/cd9DlY+7cdvp3R3jANBgkqhkiG9w0BAQsFADBmMRAwDgYDVQQK\n" +
+ "DAdCaXRtYXNrMRwwGgYDVQQLDBNodHRwczovL2JpdG1hc2submV0MTQwMgYDVQQDDCtCaXRtYXNr\n" +
+ "IFJvb3QgQ0EgKGNsaWVudCBjZXJ0aWZpY2F0ZXMgb25seSEpMB4XDTE0MTIwNTAwMDAwMFoXDTE1\n" +
+ "MDMwNTAwMDAwMFowLTErMCkGA1UEAwwiVU5MSU1JVEVEZDBwZDdkMzE4eTNtOHNkeXllaTFqYmZl\n" +
+ "eDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANRNhZ4aCwdL5+OKObOKeI2rDqEwGnIr\n" +
+ "hL9wzo/FXbwLfdW45Y9Mxwhh6xy2NkA1YUKCB8VNBKNXlBrGr1QriLbu1rItsJ2VVLqGluVV/gO4\n" +
+ "jcaPU+/Wu0hMFKG28J/dPvIGeNbjBWk6mxQAA5WIpRK9RTeQ88wVaGIZDDzIdivza2zpcyiPAyii\n" +
+ "dbkyXh7sLsKvbZB6wLrert6Y1ylR3SlkZP0LfdGAMAdkMyuXKOjgcSnUltR8HSBuZcSUlsTVM11n\n" +
+ "rYeGCYyPNNQ3UYatDW33UASgRDBorrmjhhKP7IW/opdlnPk5ZrP3i0qI32/boRe0EWZGXJvr4P3K\n" +
+ "dJ30uCECAwEAAaNvMG0wHQYDVR0OBBYEFK8bMVAM4GBB5sHptoIOAaIvlYueMAsGA1UdDwQEAwIH\n" +
+ "gDATBgNVHSUEDDAKBggrBgEFBQcDAjAJBgNVHRMEAjAAMB8GA1UdIwQYMBaAFId+E7bsWFsUWah9\n" +
+ "vZuPvZ7O+aJsMA0GCSqGSIb3DQEBCwUAA4ICAQAQOX81csVhvP422NKkZH7+g3npBpl+sEHedaGR\n" +
+ "xYPOu4HrA4TVF9h44sljRoRJyenGNdBZCXcLKHg889eePTf8Z5K3lTojp6hvwyA6tgxOMHT1kESW\n" +
+ "PfqnRw8mHfHJuE3g+4YNUMwggzwc/VZATdV/7M33sarVN9AUOHou9n9BizgCC+UnYlS+F2POumE3\n" +
+ "FbOhKo5uubI02MwBYlN2JVO2TBt1Q20w8wc6cU07Xi5Epp+1mkgFiOShkNtPcJmEyBWJhxDtSDOW\n" +
+ "2doqWYNqH2kq7B5R/kyyfcpFJqAnBTV7xs+C5rTS1mW7LpxfdCUMbYuLCpyxpO3A/DhAm8n47tUH\n" +
+ "lBtmo8Avdb8VdFpYiGBpB0o9kTFcsWFb2GkWFBduGfSEB8jUI7QtqhgZqocAKK/cweSRV8FwyUcn\n" +
+ "R0prRm3QEi9fbXqEddzjSY9y/lqWYzT7u+IOAQpKroeZ4wzgYperDNOUFuYk1rP7yuvjP2pV5rcN\n" +
+ "yPoBP60TPVWMRM4WJm6nTogAz2qBrFsf/XwT/ajzbsjT6HNB7QbRE+wkFkqspoXG5Agp7KQ8lW3L\n" +
+ "SKCDGOQJz7VIE85pD0tg7QEXBEw8oaRZtMjQ0Gvs25mxXAKka4wGasaWfYH6d0E+iKYcWn86V1rH\n" +
+ "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" +
+ "-----END CERTIFICATE-----\n" +
+ "</cert>\n" +
+ "remote-cert-tls server\n" +
+ "persist-tun\n" +
+ "auth-retry nointeract";
+
+
+ @Before
+ public void setUp() throws Exception {
+ generalConfig = new JSONObject(TestUtils.getInputAsString(getClass().getClassLoader().getResourceAsStream("general_configuration.json")));
+ secrets = new JSONObject(TestUtils.getInputAsString(getClass().getClassLoader().getResourceAsStream("secrets.json")));
+
+ }
+ @Test
+ public void testGenerate_tcp_udp() throws Exception {
+ gateway = new JSONObject(TestUtils.getInputAsString(getClass().getClassLoader().getResourceAsStream("gateway_tcp_udp.json")));
+ vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway);
+
+ String vpnConfig = vpnConfigGenerator.generate();
+ assertTrue(vpnConfig.equals(expectedVPNConfig_tcp_udp));
+ }
+
+ @Test
+ public void testGenerate_udp_tcp() throws Exception {
+ gateway = new JSONObject(TestUtils.getInputAsString(getClass().getClassLoader().getResourceAsStream("gateway_udp_tcp.json")));
+ vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway);
+
+ String vpnConfig = vpnConfigGenerator.generate();
+ assertTrue(vpnConfig.equals(expectedVPNConfig_udp_tcp));
+ }
+
+} \ No newline at end of file
diff --git a/app/src/test/resources/gateway_tcp_udp.json b/app/src/test/resources/gateway_tcp_udp.json
new file mode 100644
index 00000000..51a19ec9
--- /dev/null
+++ b/app/src/test/resources/gateway_tcp_udp.json
@@ -0,0 +1 @@
+{"location":"seattle__wa","ip_address":"198.252.153.84","capabilities":{"limited":false,"ports":["443"],"adblock":false,"transport":["openvpn"],"filter_dns":false,"protocols":["tcp","udp"],"user_ips":false},"host":"millipede.demo.bitmask.net"}
diff --git a/app/src/test/resources/gateway_udp_tcp.json b/app/src/test/resources/gateway_udp_tcp.json
new file mode 100644
index 00000000..36d0ebc2
--- /dev/null
+++ b/app/src/test/resources/gateway_udp_tcp.json
@@ -0,0 +1 @@
+{"location":"seattle__wa","ip_address":"198.252.153.84","capabilities":{"limited":false,"ports":["443"],"adblock":false,"transport":["openvpn"],"filter_dns":false,"protocols":["udp","tcp"],"user_ips":false},"host":"millipede.demo.bitmask.net"}
diff --git a/app/src/test/resources/general_configuration.json b/app/src/test/resources/general_configuration.json
new file mode 100644
index 00000000..33b0c0b5
--- /dev/null
+++ b/app/src/test/resources/general_configuration.json
@@ -0,0 +1 @@
+{"auth":"SHA1","cipher":"AES-128-CBC","keepalive":"10 30","tls-cipher":"DHE-RSA-AES128-SHA","tun-ipv6":true} \ No newline at end of file
diff --git a/ics-openvpn b/ics-openvpn
-Subproject 05b9a9ce15dc139a7ff97b3052dec8fd2e3207e
+Subproject 455ec6337157118b6d2e49808f25fd80d164956