From ae8341cf1f563fbcf2bdd6a4eff9525f42e9e995 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 10 Jan 2018 17:14:45 +0100 Subject: 8773 more test cases and clean-up --- .../bitmaskclient/eip/ProviderApiManagerTest.java | 96 ++++++++++++++++++++- .../BackendMockResponses/BackendMockProvider.java | 86 +++++++++++++++++++ .../BackendMockResponses/BaseBackendResponse.java | 75 +++++++++++++++++ .../NoErrorBackendResponse.java | 89 ++++++++++++++++++++ .../UpdatedCertificateBackendResponse.java | 97 ++++++++++++++++++++++ .../bitmaskclient/testutils/TestSetupHelper.java | 15 +--- .../testutils/answers/BackendAnswerFabric.java | 82 ------------------ .../testutils/answers/NoErrorAnswer.java | 58 ------------- .../testutils/matchers/BundleMatcher.java | 16 ++++ app/src/test/resources/error_messages.json | 2 +- app/src/test/resources/outdated_cert.pem | 33 ++++++++ app/src/test/resources/updated_cert.pem | 33 ++++++++ 12 files changed, 525 insertions(+), 157 deletions(-) create mode 100644 app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BackendMockProvider.java create mode 100644 app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BaseBackendResponse.java create mode 100644 app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/NoErrorBackendResponse.java create mode 100644 app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/UpdatedCertificateBackendResponse.java delete mode 100644 app/src/test/java/se/leap/bitmaskclient/testutils/answers/BackendAnswerFabric.java delete mode 100644 app/src/test/java/se/leap/bitmaskclient/testutils/answers/NoErrorAnswer.java create mode 100644 app/src/test/resources/outdated_cert.pem create mode 100644 app/src/test/resources/updated_cert.pem (limited to 'app/src/test') diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java index c39681c4..9ca90b17 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java @@ -49,6 +49,8 @@ import static se.leap.bitmaskclient.ProviderAPI.ERRORS; import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_NOK; import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_OK; import static se.leap.bitmaskclient.ProviderAPI.RESULT_KEY; +import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_UPDATED_CERTIFICATE; +import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.NO_ERROR; import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString; import static se.leap.bitmaskclient.testutils.TestSetupHelper.mockBundle; import static se.leap.bitmaskclient.testutils.TestSetupHelper.mockClientGenerator; @@ -58,7 +60,7 @@ import static se.leap.bitmaskclient.testutils.TestSetupHelper.mockProviderApiCon import static se.leap.bitmaskclient.testutils.TestSetupHelper.mockResources; import static se.leap.bitmaskclient.testutils.TestSetupHelper.mockResultReceiver; import static se.leap.bitmaskclient.testutils.TestSetupHelper.mockTextUtils; -import static se.leap.bitmaskclient.testutils.answers.BackendAnswerFabric.TestBackendErrorCase.NO_ERROR; + /** * Created by cyberta on 04.01.18. @@ -188,7 +190,7 @@ public class ProviderApiManagerTest { providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); Bundle expectedResult = mockBundle(); expectedResult.putBoolean(RESULT_KEY, false); - expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_CERTIFICATE_PINNING\",\"errors\":\"Stored provider certificate is corrupted. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}"); + expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_CERTIFICATE_PINNING\",\"errors\":\"Stored provider certificate is invalid. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}"); Intent provider_API_command = mockIntent(); Bundle parameters = mockBundle(); @@ -210,7 +212,7 @@ public class ProviderApiManagerTest { providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); Bundle expectedResult = mockBundle(); expectedResult.putBoolean(RESULT_KEY, false); - expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_CERTIFICATE_PINNING\",\"errors\":\"Stored provider certificate is corrupted. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}"); + expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_CERTIFICATE_PINNING\",\"errors\":\"Stored provider certificate is invalid. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}"); Intent provider_API_command = mockIntent(); Bundle parameters = mockBundle(); @@ -232,11 +234,33 @@ public class ProviderApiManagerTest { providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); Bundle expectedResult = mockBundle(); expectedResult.putBoolean(RESULT_KEY, false); - expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_CERTIFICATE_PINNING\",\"errors\":\"Stored provider certificate is corrupted. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}"); + expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_CERTIFICATE_PINNING\",\"errors\":\"Stored provider certificate is invalid. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}"); + + Intent provider_API_command = mockIntent(); + Bundle parameters = mockBundle(); + parameters.putString(Provider.MAIN_URL, "https://riseup.net"); + + provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + + providerApiManager.handleIntent(provider_API_command); + } + + + @Test + public void test_handleIntentSetupProvider_preseededProviderAndCA_outdatedCertificate() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { + mockProviderApiConnector(NO_ERROR); + providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); + Bundle expectedResult = mockBundle(); + expectedResult.putBoolean(RESULT_KEY, false); + expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_INVALID_CERTIFICATE\",\"errors\":\"Stored provider certificate is expired. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}"); Intent provider_API_command = mockIntent(); Bundle parameters = mockBundle(); parameters.putString(Provider.MAIN_URL, "https://riseup.net"); + parameters.putString(Provider.CA_CERT, getInputAsString(getClass().getClassLoader().getResourceAsStream("outdated_cert.pem"))); + parameters.putString(Provider.KEY, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))); provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); @@ -245,5 +269,69 @@ public class ProviderApiManagerTest { providerApiManager.handleIntent(provider_API_command); } + @Test + public void test_handleIntentSetupProvider_storedProviderAndCAFromPreviousSetup_outdatedCertificate() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { + mockProviderApiConnector(NO_ERROR); + mockPreferences.edit().putString(Provider.KEY + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))).apply(); + mockPreferences.edit().putString(Provider.CA_CERT + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("outdated_cert.pem"))).apply(); + providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); + Bundle expectedResult = mockBundle(); + expectedResult.putBoolean(RESULT_KEY, false); + expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_INVALID_CERTIFICATE\",\"errors\":\"Stored provider certificate is expired. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}"); + Intent provider_API_command = mockIntent(); + Bundle parameters = mockBundle(); + parameters.putString(Provider.MAIN_URL, "https://riseup.net"); + + provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + + providerApiManager.handleIntent(provider_API_command); + } + + @Test + public void test_handleIntentSetupProvider_preseededProviderAndCA_ValidCertificateButUpdatedCertificateOnServerSide() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { + mockFingerprintForCertificate(" a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); + mockProviderApiConnector(ERROR_CASE_UPDATED_CERTIFICATE); + + providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); + Bundle expectedResult = mockBundle(); + expectedResult.putBoolean(RESULT_KEY, false); + expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_INVALID_CERTIFICATE\",\"errors\":\"Stored provider certificate is invalid. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}"); + + Intent provider_API_command = mockIntent(); + Bundle parameters = mockBundle(); + parameters.putString(Provider.MAIN_URL, "https://riseup.net"); + parameters.putString(Provider.CA_CERT, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem"))); + parameters.putString(Provider.KEY, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))); + + provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + + providerApiManager.handleIntent(provider_API_command); + } + + @Test + public void test_handleIntentSetupProvider_storedProviderAndCAFromPreviousSetup_ValidCertificateButUpdatedCertificateOnServerSide() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { + mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); + mockProviderApiConnector(ERROR_CASE_UPDATED_CERTIFICATE); + mockPreferences.edit().putString(Provider.KEY + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))).apply(); + mockPreferences.edit().putString(Provider.CA_CERT + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem"))).apply(); + providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); + Bundle expectedResult = mockBundle(); + expectedResult.putBoolean(RESULT_KEY, false); + expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_INVALID_CERTIFICATE\",\"errors\":\"Stored provider certificate is invalid. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}"); + + Intent provider_API_command = mockIntent(); + Bundle parameters = mockBundle(); + parameters.putString(Provider.MAIN_URL, "https://riseup.net"); + + provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + + providerApiManager.handleIntent(provider_API_command); + } } diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BackendMockProvider.java b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BackendMockProvider.java new file mode 100644 index 00000000..9069661f --- /dev/null +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BackendMockProvider.java @@ -0,0 +1,86 @@ +/** + * 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 . + */ +package se.leap.bitmaskclient.testutils.BackendMockResponses; + +import java.io.IOException; + +/** + * Created by cyberta on 10.01.18. + */ + +public class BackendMockProvider { + /** + * This enum can be useful to provide different responses from a mocked ProviderApiConnector + * in order to test different error scenarios + */ + public enum TestBackendErrorCase { + NO_ERROR, + ERROR_CASE_UPDATED_CERTIFICATE, + ERROR_NO_RESPONSE_BODY, // => NullPointerException + ERROR_DNS_RESOLUTION_ERROR, // => UnkownHostException + ERROR_SOCKET_TIMEOUT, // => SocketTimeoutException + ERROR_WRONG_PROTOCOL, // => MalformedURLException + ERROR_CERTIFICATE_INVALID, // => SSLHandshakeException + ERROR_WRONG_PORT, // => ConnectException + ERROR_PAYLOAD_MISSING, // => IllegalArgumentException + ERROR_TLS_1_2_NOT_SUPPORTED, // => UnknownServiceException + ERROR_UNKNOWN_IO_EXCEPTION, // => IOException + ERROR_NO_ACCESS, + ERROR_INVALID_SESSION_TOKEN, + ERROR_NO_CONNECTION, + ERROR_WRONG_SRP_CREDENTIALS + } + + + public static void provideBackendResponsesFor(TestBackendErrorCase errorCase) throws IOException { + switch (errorCase) { + + case NO_ERROR: + new NoErrorBackendResponse(); + break; + case ERROR_CASE_UPDATED_CERTIFICATE: + new UpdatedCertificateBackendResponse(); + break; + case ERROR_NO_RESPONSE_BODY: + break; + case ERROR_DNS_RESOLUTION_ERROR: + break; + case ERROR_SOCKET_TIMEOUT: + break; + case ERROR_WRONG_PROTOCOL: + break; + case ERROR_CERTIFICATE_INVALID: + break; + case ERROR_WRONG_PORT: + break; + case ERROR_PAYLOAD_MISSING: + break; + case ERROR_TLS_1_2_NOT_SUPPORTED: + break; + case ERROR_UNKNOWN_IO_EXCEPTION: + break; + case ERROR_NO_ACCESS: + break; + case ERROR_INVALID_SESSION_TOKEN: + break; + case ERROR_NO_CONNECTION: + break; + case ERROR_WRONG_SRP_CREDENTIALS: + break; + } + } +} diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BaseBackendResponse.java b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BaseBackendResponse.java new file mode 100644 index 00000000..98224019 --- /dev/null +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BaseBackendResponse.java @@ -0,0 +1,75 @@ +/** + * 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 . + */ +package se.leap.bitmaskclient.testutils.BackendMockResponses; + +import android.util.Pair; + +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.mockito.stubbing.Answer; + +import java.io.IOException; + +import okhttp3.OkHttpClient; +import se.leap.bitmaskclient.ProviderApiConnector; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.nullable; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + +/** + * Created by cyberta on 10.01.18. + */ + +public abstract class BaseBackendResponse { + + private Answer answerRequestStringFromServer; + private Answer answerCanConnect; + private Answer answerDelete; + + public BaseBackendResponse() throws IOException { + mockStatic(ProviderApiConnector.class); + this.answerRequestStringFromServer = getAnswerForRequestStringFromServer(); + this.answerCanConnect = getAnswerForCanConnect(); + this.answerDelete = getAnswerForDelete(); + + responseOnRequestStringFromServer(); + responseOnCanConnect(); + responseOnDelete(); + + } + + public abstract Answer getAnswerForRequestStringFromServer(); + public abstract Answer getAnswerForCanConnect(); + public abstract Answer getAnswerForDelete(); + + + public void responseOnRequestStringFromServer() throws IOException, RuntimeException { + Mockito.when(ProviderApiConnector.requestStringFromServer(anyString(), anyString(), nullable(String.class), ArgumentMatchers.>anyList(), any(OkHttpClient.class))). + thenAnswer(answerRequestStringFromServer); + } + + public void responseOnCanConnect() throws IOException, RuntimeException { + Mockito.when(ProviderApiConnector.canConnect(any(OkHttpClient.class), anyString())).thenAnswer(answerCanConnect); + } + + public void responseOnDelete() throws IOException, RuntimeException { + Mockito.when(ProviderApiConnector.delete(any(OkHttpClient.class), anyString())).thenAnswer(answerDelete); + } + +} diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/NoErrorBackendResponse.java b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/NoErrorBackendResponse.java new file mode 100644 index 00000000..fa318e42 --- /dev/null +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/NoErrorBackendResponse.java @@ -0,0 +1,89 @@ +/** + * 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 . + */ +package se.leap.bitmaskclient.testutils.BackendMockResponses; + +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.io.IOException; + +import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString; + +/** + * Created by cyberta on 10.01.18. + */ + +public class NoErrorBackendResponse extends BaseBackendResponse { + public NoErrorBackendResponse() throws IOException { + super(); + } + + @Override + public Answer getAnswerForRequestStringFromServer() { + return new Answer() { + @Override + public String answer(InvocationOnMock invocation) throws Throwable { + String url = (String) invocation.getArguments()[0]; + String requestMethod = (String) invocation.getArguments()[1]; + String jsonPayload = (String) invocation.getArguments()[2]; + + if (url.contains("/provider.json")) { + //download provider json + return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json")); + } else if (url.contains("/ca.crt")) { + //download provider ca cert + return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem")); + } else if (url.contains("config/eip-service.json")) { + // download provider service json containing gateways, locations and openvpn settings + return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.service.json")); + } else if (url.contains("/users.json")) { + //create new user + //TODO: implement me + } else if (url.contains("/sessions.json")) { + //srp auth: sendAToSRPServer + //TODO: implement me + } else if (url.contains("/sessions/parmegvtest10.json")){ + //srp auth: sendM1ToSRPServer + //TODO: implement me + } + + return null; + } + }; + } + + @Override + public Answer getAnswerForCanConnect() { + return new Answer() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + return true; + } + }; + } + + @Override + public Answer getAnswerForDelete() { + return new Answer() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + return true; + } + }; + } + +} diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/UpdatedCertificateBackendResponse.java b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/UpdatedCertificateBackendResponse.java new file mode 100644 index 00000000..232649a1 --- /dev/null +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/UpdatedCertificateBackendResponse.java @@ -0,0 +1,97 @@ +/** + * 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 . + */ +package se.leap.bitmaskclient.testutils.BackendMockResponses; + +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.io.IOException; + +import javax.net.ssl.SSLHandshakeException; + +import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString; + +/** + * Created by cyberta on 10.01.18. + */ + +public class UpdatedCertificateBackendResponse extends BaseBackendResponse { + static volatile boolean wasCACertCalled = false; + + + public UpdatedCertificateBackendResponse() throws IOException { + super(); + } + + @Override + public Answer getAnswerForRequestStringFromServer() { + return new Answer() { + + @Override + public String answer(InvocationOnMock invocation) throws Throwable { + String url = (String) invocation.getArguments()[0]; + + if (url.contains("/provider.json")) { + if (!wasCACertCalled) { + throw new SSLHandshakeException("Updated certificate on server side"); + } + //download provider json + return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json")); + } else if (url.contains("/ca.crt")) { + //download provider ca cert + wasCACertCalled = true; + return getInputAsString(getClass().getClassLoader().getResourceAsStream("updated_cert.pem")); + } else if (url.contains("config/eip-service.json")) { + // download provider service json containing gateways, locations and openvpn settings + if (!wasCACertCalled) { + throw new SSLHandshakeException("Updated certificate on server side"); + } + return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.service.json")); + } + + return null; + } + }; + } + + @Override + public Answer getAnswerForCanConnect() { + return new Answer() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + if (!wasCACertCalled) { + throw new SSLHandshakeException("Updated certificate on server side"); + } + return true; + } + }; + } + + @Override + public Answer getAnswerForDelete() { + return new Answer() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + if (!wasCACertCalled) { + throw new SSLHandshakeException("Updated certificate on server side"); + } + return true; + } + }; + } + +} diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/TestSetupHelper.java b/app/src/test/java/se/leap/bitmaskclient/testutils/TestSetupHelper.java index 19d7e13f..f8f70eaf 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/TestSetupHelper.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/TestSetupHelper.java @@ -24,11 +24,9 @@ import android.os.Parcelable; import android.os.ResultReceiver; import android.support.annotation.NonNull; import android.text.TextUtils; -import android.util.Pair; import org.json.JSONException; import org.json.JSONObject; -import org.mockito.ArgumentMatchers; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -50,9 +48,8 @@ import java.util.Set; import okhttp3.OkHttpClient; import se.leap.bitmaskclient.ConfigHelper; import se.leap.bitmaskclient.OkHttpClientGenerator; -import se.leap.bitmaskclient.ProviderApiConnector; import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.testutils.answers.BackendAnswerFabric; +import se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider; import se.leap.bitmaskclient.testutils.matchers.BundleMatcher; import static org.junit.Assert.assertEquals; @@ -61,14 +58,11 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.powermock.api.mockito.PowerMockito.mockStatic; -import static se.leap.bitmaskclient.testutils.answers.BackendAnswerFabric.TestBackendErrorCase.ERROR_NO_CONNECTION; -import static se.leap.bitmaskclient.testutils.answers.BackendAnswerFabric.getAnswerForErrorcase; /** * Created by cyberta on 08.10.17. @@ -383,14 +377,11 @@ public class TestSetupHelper { mockStatic(ConfigHelper.class); when(ConfigHelper.getFingerprintFromCertificate(any(X509Certificate.class), anyString())).thenReturn(mockedFingerprint); when(ConfigHelper.checkErroneousDownload(anyString())).thenCallRealMethod(); - when(ConfigHelper.base64toHex(anyString())).thenCallRealMethod(); when(ConfigHelper.parseX509CertificateFromString(anyString())).thenCallRealMethod(); } - public static void mockProviderApiConnector(final BackendAnswerFabric.TestBackendErrorCase errorCase) throws IOException { - mockStatic(ProviderApiConnector.class); - when(ProviderApiConnector.canConnect(any(OkHttpClient.class), anyString())).thenReturn(errorCase != ERROR_NO_CONNECTION); - when(ProviderApiConnector.requestStringFromServer(anyString(), anyString(), nullable(String.class), ArgumentMatchers.>anyList(), any(OkHttpClient.class))).thenAnswer(getAnswerForErrorcase(errorCase)); + public static void mockProviderApiConnector(final BackendMockProvider.TestBackendErrorCase errorCase) throws IOException { + BackendMockProvider.provideBackendResponsesFor(errorCase); } public static OkHttpClientGenerator mockClientGenerator() { diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/answers/BackendAnswerFabric.java b/app/src/test/java/se/leap/bitmaskclient/testutils/answers/BackendAnswerFabric.java deleted file mode 100644 index 00e276f4..00000000 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/answers/BackendAnswerFabric.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * 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 . - */ - -package se.leap.bitmaskclient.testutils.answers; - -import org.mockito.stubbing.Answer; - -/** - * Created by cyberta on 09.01.18. - */ - -public class BackendAnswerFabric { - /** - * This enum can be useful to provide different responses from a mocked ProviderApiConnector - * in order to test different error scenarios - */ - public enum TestBackendErrorCase { - NO_ERROR, - ERROR_NO_RESPONSE_BODY, // => NullPointerException - ERROR_DNS_RESOLUTION_ERROR, // => UnkownHostException - ERROR_SOCKET_TIMEOUT, // => SocketTimeoutException - ERROR_WRONG_PROTOCOL, // => MalformedURLException - ERROR_CERTIFICATE_INVALID, // => SSLHandshakeException - ERROR_WRONG_PORT, // => ConnectException - ERROR_PAYLOAD_MISSING, // => IllegalArgumentException - ERROR_TLS_1_2_NOT_SUPPORTED, // => UnknownServiceException - ERROR_UNKNOWN_IO_EXCEPTION, // => IOException - ERROR_NO_ACCESS, - ERROR_INVALID_SESSION_TOKEN, - ERROR_NO_CONNECTION, - ERROR_WRONG_SRP_CREDENTIALS - } - - public static Answer getAnswerForErrorcase(TestBackendErrorCase errorCase) { - switch (errorCase) { - case NO_ERROR: - return new NoErrorAnswer(); - case ERROR_NO_RESPONSE_BODY: - break; - case ERROR_DNS_RESOLUTION_ERROR: - break; - case ERROR_SOCKET_TIMEOUT: - break; - case ERROR_WRONG_PROTOCOL: - break; - case ERROR_CERTIFICATE_INVALID: - break; - case ERROR_WRONG_PORT: - break; - case ERROR_PAYLOAD_MISSING: - break; - case ERROR_TLS_1_2_NOT_SUPPORTED: - break; - case ERROR_UNKNOWN_IO_EXCEPTION: - break; - case ERROR_NO_ACCESS: - break; - case ERROR_INVALID_SESSION_TOKEN: - break; - case ERROR_NO_CONNECTION: - break; - case ERROR_WRONG_SRP_CREDENTIALS: - break; - } - return null; - } - -} diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/answers/NoErrorAnswer.java b/app/src/test/java/se/leap/bitmaskclient/testutils/answers/NoErrorAnswer.java deleted file mode 100644 index cbf9f6b8..00000000 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/answers/NoErrorAnswer.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * 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 . - */ - -package se.leap.bitmaskclient.testutils.answers; - -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString; - -/** - * Created by cyberta on 09.01.18. - */ - -public class NoErrorAnswer implements Answer { - @Override - public String answer(InvocationOnMock invocation) throws Throwable { - String url = (String) invocation.getArguments()[0]; - String requestMethod = (String) invocation.getArguments()[1]; - String jsonPayload = (String) invocation.getArguments()[2]; - - if (url.contains("/provider.json")) { - //download provider json - return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json")); - } else if (url.contains("/ca.crt")) { - //download provider ca cert - return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem")); - } else if (url.contains("config/eip-service.json")) { - // download provider service json containing gateways, locations and openvpn settings - return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.service.json")); - } else if (url.contains("/users.json")) { - //create new user - //TODO: implement me - } else if (url.contains("/sessions.json")) { - //srp auth: sendAToSRPServer - //TODO: implement me - } else if (url.contains("/sessions/parmegvtest10.json")){ - //srp auth: sendM1ToSRPServer - //TODO: implement me - } - - return null; - } -} diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/matchers/BundleMatcher.java b/app/src/test/java/se/leap/bitmaskclient/testutils/matchers/BundleMatcher.java index a7867e08..d2d2a102 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/matchers/BundleMatcher.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/matchers/BundleMatcher.java @@ -1,3 +1,19 @@ +/** + * 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 . + */ package se.leap.bitmaskclient.testutils.matchers; import android.os.Bundle; diff --git a/app/src/test/resources/error_messages.json b/app/src/test/resources/error_messages.json index 486a3dab..4d72b074 100644 --- a/app/src/test/resources/error_messages.json +++ b/app/src/test/resources/error_messages.json @@ -11,6 +11,6 @@ "error_json_exception_user_message": "Try again: Bad response from the server", "error_no_such_algorithm_exception_user_message": "Encryption algorithm not found. Please update your OS!", "warning_corrupted_provider_details": "Stored provider details are corrupted. You can either update Bitmask (recommended) or update the provider details using a commercial CA certificate.", -"warning_corrupted_provider_cert": "Stored provider certificate is corrupted. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.", +"warning_corrupted_provider_cert": "Stored provider certificate is invalid. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.", "warning_expired_provider_cert": "Stored provider certificate is expired. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate." } \ No newline at end of file diff --git a/app/src/test/resources/outdated_cert.pem b/app/src/test/resources/outdated_cert.pem new file mode 100644 index 00000000..269efe5f --- /dev/null +++ b/app/src/test/resources/outdated_cert.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/app/src/test/resources/updated_cert.pem b/app/src/test/resources/updated_cert.pem new file mode 100644 index 00000000..21f9a693 --- /dev/null +++ b/app/src/test/resources/updated_cert.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- -- cgit v1.2.3