diff --git a/ui/src/main/java/com/wireguard/android/activity/LoginActivity.java b/ui/src/main/java/com/wireguard/android/activity/LoginActivity.java index 35fae1d..c442f27 100644 --- a/ui/src/main/java/com/wireguard/android/activity/LoginActivity.java +++ b/ui/src/main/java/com/wireguard/android/activity/LoginActivity.java @@ -1,10 +1,12 @@ package com.wireguard.android.activity; +import androidx.annotation.Nullable; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; import android.content.Intent; import android.os.Bundle; +import android.security.KeyChain; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; @@ -18,6 +20,10 @@ import com.wireguard.android.repository.DataRepository; import com.wireguard.android.resource.StatusResource; import com.wireguard.android.viewmodel.LoginViewModel; +import javax.security.cert.CertificateEncodingException; +import javax.security.cert.CertificateException; +import javax.security.cert.X509Certificate; + public class LoginActivity extends BaseActivityBubble { private LoginViewModel loginViewModel; @@ -29,6 +35,8 @@ public class LoginActivity extends BaseActivityBubble { private static final String BASE_URL_PREFIX = "https://"; private static final String BASE_URL_SUFFIX = ":1443/api/"; private static final String SEPARATOR = "\\."; + private static final int REQUEST_CODE = 1555; + private static final String CERTIFICATE_NAME = "Bubble Certificate"; @Override protected void onCreate(Bundle savedInstanceState) { @@ -47,17 +55,16 @@ public class LoginActivity extends BaseActivityBubble { sign.setOnClickListener(new OnClickListener() { @Override public void onClick(final View v) { final String url = BASE_URL_PREFIX + bubbleName.getText().toString() + BASE_URL_SUFFIX; - if(url.split(SEPARATOR).length!=3){ - Toast.makeText(LoginActivity.this,getResources().getText(R.string.hostname_not_valid),Toast.LENGTH_LONG).show(); + if (url.split(SEPARATOR).length != 3) { + Toast.makeText(LoginActivity.this, getResources().getText(R.string.hostname_not_valid), Toast.LENGTH_LONG).show(); return; } - if(DataRepository.getRepositoryInstance()==null) { + if (DataRepository.getRepositoryInstance() == null) { loginViewModel.buildRepositoryInstance(LoginActivity.this, url); - } - else { + } else { loginViewModel.buildClientService(url); } - loginViewModel.setUserURL(LoginActivity.this,url); + loginViewModel.setUserURL(LoginActivity.this, url); final String usernameInput = userName.getText().toString().trim(); final String passwordInput = password.getText().toString().trim(); showLoadingDialog(); @@ -78,23 +85,50 @@ public class LoginActivity extends BaseActivityBubble { @Override public void onChanged(final StatusResource userStatusResource) { switch (userStatusResource.status) { case SUCCESS: - Toast.makeText(LoginActivity.this, "Success", Toast.LENGTH_SHORT).show(); - Log.d("TAG", "Success"); - closeLoadingDialog(); - Intent intent = new Intent(LoginActivity.this, MainActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - startActivity(intent); + loginViewModel.getCertificate(LoginActivity.this).observe(LoginActivity.this, new Observer() { + @Override public void onChanged(final String s) { + closeLoadingDialog(); + final byte[] cert = s.getBytes(); + final Intent intent = KeyChain.createInstallIntent(); + X509Certificate x509Certificate = null; + try { + x509Certificate = X509Certificate.getInstance(cert); + } catch (final CertificateException e) { + e.printStackTrace(); + } + try { + intent.putExtra(KeyChain.EXTRA_CERTIFICATE, x509Certificate.getEncoded()); + } catch (final CertificateEncodingException e) { + e.printStackTrace(); + } + intent.putExtra(KeyChain.EXTRA_NAME, CERTIFICATE_NAME); + startActivityForResult(intent, REQUEST_CODE); + } + }); break; case LOADING: Log.d("TAG", "Loading"); break; case ERROR: closeLoadingDialog(); - Toast.makeText(LoginActivity.this, "Login Failed", Toast.LENGTH_SHORT).show(); + Toast.makeText(LoginActivity.this, getString(R.string.login_failed), Toast.LENGTH_SHORT).show(); Log.d("TAG", "Error"); break; } } }); } + + @Override protected void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) { + Toast.makeText(this, getString(R.string.success), Toast.LENGTH_SHORT).show(); + Log.d("TAG", "Success"); + final Intent mainActivityIntent = new Intent(this, MainActivity.class); + mainActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(mainActivityIntent); + } else { + Toast.makeText(this, getString(R.string.cerificate_install), Toast.LENGTH_LONG).show(); + } + } } diff --git a/ui/src/main/java/com/wireguard/android/api/ApiConstants.java b/ui/src/main/java/com/wireguard/android/api/ApiConstants.java index f801759..4b4665b 100644 --- a/ui/src/main/java/com/wireguard/android/api/ApiConstants.java +++ b/ui/src/main/java/com/wireguard/android/api/ApiConstants.java @@ -11,4 +11,5 @@ public class ApiConstants { public static final String AUTHORIZATION_HEADER = "X-Bubble-Session"; public static final String DEVICE_NAME = "name"; public static final String DEVICE_TYPE = "deviceType"; + public static final String CERTIFICATE_URL = "auth/cacert?deviceType=android"; } diff --git a/ui/src/main/java/com/wireguard/android/repository/DataRepository.java b/ui/src/main/java/com/wireguard/android/repository/DataRepository.java index 5b4e60a..dc394a3 100644 --- a/ui/src/main/java/com/wireguard/android/repository/DataRepository.java +++ b/ui/src/main/java/com/wireguard/android/repository/DataRepository.java @@ -363,4 +363,24 @@ public class DataRepository { }); return liveData; } + + public MutableLiveData getCertificate(Context context){ + final MutableLiveData liveData = new MutableLiveData<>(); + final Request request = new Request.Builder() + .url(BASE_URL + ApiConstants.CERTIFICATE_URL) + .build(); + client.newCall(request).enqueue(new Callback() { + @Override public void onFailure(final okhttp3.Call call, final IOException e) { + + } + + @Override public void onResponse(final okhttp3.Call call, final Response response) throws IOException { + final InputStream inputStream = response.body().byteStream(); + final Scanner scanner = new Scanner(inputStream).useDelimiter(DELIMITER); + final String data = scanner.hasNext() ? scanner.next() : ""; + liveData.postValue(data); + } + }); + return liveData; + } } diff --git a/ui/src/main/java/com/wireguard/android/viewmodel/LoginViewModel.java b/ui/src/main/java/com/wireguard/android/viewmodel/LoginViewModel.java index 18f55ee..542ee20 100644 --- a/ui/src/main/java/com/wireguard/android/viewmodel/LoginViewModel.java +++ b/ui/src/main/java/com/wireguard/android/viewmodel/LoginViewModel.java @@ -8,6 +8,7 @@ import com.wireguard.android.resource.StatusResource; import com.wireguard.android.util.UserStore; import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; public class LoginViewModel extends ViewModel { @@ -31,4 +32,8 @@ public class LoginViewModel extends ViewModel { public void buildClientService(String url){ DataRepository.getRepositoryInstance().buildClientService(url); } + + public MutableLiveData getCertificate(Context context){ + return DataRepository.getRepositoryInstance().getCertificate(context); + } } diff --git a/ui/src/main/res/values/strings.xml b/ui/src/main/res/values/strings.xml index 55e5023..9085aff 100644 --- a/ui/src/main/res/values/strings.xml +++ b/ui/src/main/res/values/strings.xml @@ -247,4 +247,7 @@ Failed Disconnect Hostname not valid + Login Failed + "Please install a certificate" + Success