diff --git a/src/frontends/android/app/build.gradle b/src/frontends/android/app/build.gradle index b2d8c0b95..b3a17f373 100644 --- a/src/frontends/android/app/build.gradle +++ b/src/frontends/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "org.strongswan.android" minSdkVersion 15 targetSdkVersion 28 - versionCode 64 - versionName "2.1.1" + versionCode 68 + versionName "2.2.0" } sourceSets.main { @@ -46,8 +46,8 @@ android { } dependencies { - implementation 'androidx.appcompat:appcompat:1.0.0' - implementation 'androidx.preference:preference:1.0.0' + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.preference:preference:1.1.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'com.google.android.material:material:1.0.0' testImplementation 'junit:junit:4.12' diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/NetworkManager.java b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/NetworkManager.java index abe629322..e283cd56d 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/NetworkManager.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/NetworkManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Tobias Brunner + * Copyright (C) 2012-2019 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -20,7 +20,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; +import android.net.Network; import android.net.NetworkInfo; +import android.net.NetworkRequest; +import android.os.Build; import java.util.LinkedList; @@ -28,12 +31,45 @@ public class NetworkManager extends BroadcastReceiver implements Runnable { private final Context mContext; private volatile boolean mRegistered; + private ConnectivityManager.NetworkCallback mCallback; private Thread mEventNotifier; + private int mConnectedNetworks = 0; private LinkedList mEvents = new LinkedList<>(); public NetworkManager(Context context) { mContext = context; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + { + mCallback = new ConnectivityManager.NetworkCallback() + { + @Override + public void onAvailable(Network network) + { + synchronized (NetworkManager.this) + { + /* we expect this to be called if connected to at least one network during + * callback registration */ + mConnectedNetworks += 1; + mEvents.addLast(true); + NetworkManager.this.notifyAll(); + } + } + + @Override + public void onLost(Network network) + { + synchronized (NetworkManager.this) + { + /* in particular mobile connections are disconnected overlapping with WiFi */ + mConnectedNetworks -= 1; + mEvents.addLast(mConnectedNetworks > 0); + NetworkManager.this.notifyAll(); + } + } + }; + } } public void Register() @@ -42,12 +78,38 @@ public class NetworkManager extends BroadcastReceiver implements Runnable mRegistered = true; mEventNotifier = new Thread(this); mEventNotifier.start(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + { + ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); + /* while we only get events for the VPN network via registerDefaultNetworkCallback, + * the default capabilities in the builder include NetworkCapabilities.NET_CAPABILITY_NOT_VPN */ + NetworkRequest.Builder builder = new NetworkRequest.Builder(); + cm.registerNetworkCallback(builder.build(), mCallback); + } + else + { + registerLegacyReceiver(); + } + } + + @SuppressWarnings("deprecation") + private void registerLegacyReceiver() + { + /* deprecated since API level 28 */ mContext.registerReceiver(this, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); } public void Unregister() { - mContext.unregisterReceiver(this); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + { + ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); + cm.unregisterNetworkCallback(mCallback); + } + else + { + mContext.unregisterReceiver(this); + } mRegistered = false; synchronized (this) { diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificatesActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificatesActivity.java index 295379023..1c13a110f 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificatesActivity.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificatesActivity.java @@ -169,7 +169,7 @@ public class TrustedCertificatesActivity extends AppCompatActivity implements Tr public TrustedCertificatesPagerAdapter(FragmentManager fm, Context context) { - super(fm); + super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); mTabs = new TrustedCertificatesTab[]{ new TrustedCertificatesTab(context.getString(R.string.system_tab), TrustedCertificateSource.SYSTEM), new TrustedCertificatesTab(context.getString(R.string.user_tab), TrustedCertificateSource.USER), diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java index 9674b7d41..fac9b34ea 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java @@ -28,7 +28,6 @@ import android.security.KeyChain; import android.security.KeyChainAliasCallback; import android.security.KeyChainException; import android.text.Editable; -import android.text.Html; import android.text.SpannableString; import android.text.Spanned; import android.text.TextUtils; @@ -91,7 +90,6 @@ public class VpnProfileDetailActivity extends AppCompatActivity private TrustedCertificateEntry mCertEntry; private String mUserCertLoading; private CertificateIdentitiesAdapter mSelectUserIdAdapter; - private String mSelectedUserId; private TrustedCertificateEntry mUserCertEntry; private VpnType mVpnType = VpnType.IKEV2_EAP; private SelectedAppsHandling mSelectedAppsHandling = SelectedAppsHandling.SELECTED_APPS_DISABLE; @@ -108,7 +106,6 @@ public class VpnProfileDetailActivity extends AppCompatActivity private EditText mPassword; private ViewGroup mUserCertificate; private RelativeLayout mSelectUserCert; - private Spinner mSelectUserId; private CheckBox mCheckAuto; private RelativeLayout mSelectCert; private RelativeLayout mTncNotice; @@ -116,6 +113,8 @@ public class VpnProfileDetailActivity extends AppCompatActivity private ViewGroup mAdvancedSettings; private MultiAutoCompleteTextView mRemoteId; private TextInputLayoutHelper mRemoteIdWrap; + private MultiAutoCompleteTextView mLocalId; + private TextInputLayoutHelper mLocalIdWrap; private EditText mMTU; private TextInputLayoutHelper mMTUWrap; private EditText mPort; @@ -141,7 +140,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity private EditText mEspProposal; private TextView mProfileIdLabel; private TextView mProfileId; - private MultiAutoCompleteTextView mDnsServers; + private EditText mDnsServers; private TextInputLayoutHelper mDnsServersWrap; @Override @@ -171,7 +170,6 @@ public class VpnProfileDetailActivity extends AppCompatActivity mUserCertificate = (ViewGroup)findViewById(R.id.user_certificate_group); mSelectUserCert = (RelativeLayout)findViewById(R.id.select_user_certificate); - mSelectUserId = (Spinner)findViewById(R.id.select_user_id); mCheckAuto = (CheckBox)findViewById(R.id.ca_auto); mSelectCert = (RelativeLayout)findViewById(R.id.select_certificate); @@ -181,8 +179,10 @@ public class VpnProfileDetailActivity extends AppCompatActivity mRemoteId = (MultiAutoCompleteTextView)findViewById(R.id.remote_id); mRemoteIdWrap = (TextInputLayoutHelper) findViewById(R.id.remote_id_wrap); - mDnsServers = (MultiAutoCompleteTextView)findViewById(R.id.dns_servers); - mDnsServersWrap = (TextInputLayoutHelper) findViewById(R.id.dns_servers_wrap); + mLocalId = findViewById(R.id.local_id); + mLocalIdWrap = findViewById(R.id.local_id_wrap); + mDnsServers = findViewById(R.id.dns_servers); + mDnsServersWrap = findViewById(R.id.dns_servers_wrap); mMTU = (EditText)findViewById(R.id.mtu); mMTUWrap = (TextInputLayoutHelper) findViewById(R.id.mtu_wrap); mPort = (EditText)findViewById(R.id.port); @@ -217,9 +217,10 @@ public class VpnProfileDetailActivity extends AppCompatActivity final SpaceTokenizer spaceTokenizer = new SpaceTokenizer(); mName.setTokenizer(spaceTokenizer); mRemoteId.setTokenizer(spaceTokenizer); - final ArrayAdapter completeAdapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line); - mName.setAdapter(completeAdapter); - mRemoteId.setAdapter(completeAdapter); + mLocalId.setTokenizer(spaceTokenizer); + final ArrayAdapter gatewayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line); + mName.setAdapter(gatewayAdapter); + mRemoteId.setAdapter(gatewayAdapter); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { @@ -238,8 +239,8 @@ public class VpnProfileDetailActivity extends AppCompatActivity @Override public void afterTextChanged(Editable s) { - completeAdapter.clear(); - completeAdapter.add(mGateway.getText().toString()); + gatewayAdapter.clear(); + gatewayAdapter.add(mGateway.getText().toString()); if (TextUtils.isEmpty(mGateway.getText())) { mNameWrap.setHelperText(getString(R.string.profile_name_hint)); @@ -281,23 +282,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity mSelectUserCert.setOnClickListener(new SelectUserCertOnClickListener()); mSelectUserIdAdapter = new CertificateIdentitiesAdapter(this); - mSelectUserId.setAdapter(mSelectUserIdAdapter); - mSelectUserId.setOnItemSelectedListener(new OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) - { - if (mUserCertEntry != null) - { /* we don't store the subject DN as it is in the reverse order and the default anyway */ - mSelectedUserId = position == 0 ? null : mSelectUserIdAdapter.getItem(position); - } - } - - @Override - public void onNothingSelected(AdapterView parent) - { - mSelectedUserId = null; - } - }); + mLocalId.setAdapter(mSelectUserIdAdapter); mCheckAuto.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override @@ -385,10 +370,6 @@ public class VpnProfileDetailActivity extends AppCompatActivity { outState.putString(VpnProfileDataSource.KEY_USER_CERTIFICATE, mUserCertEntry.getAlias()); } - if (mSelectedUserId != null) - { - outState.putString(VpnProfileDataSource.KEY_LOCAL_ID, mSelectedUserId); - } if (mCertEntry != null) { outState.putString(VpnProfileDataSource.KEY_CERTIFICATE, mCertEntry.getAlias()); @@ -456,10 +437,10 @@ public class VpnProfileDetailActivity extends AppCompatActivity mUsernamePassword.setVisibility(mVpnType.has(VpnTypeFeature.USER_PASS) ? View.VISIBLE : View.GONE); mUserCertificate.setVisibility(mVpnType.has(VpnTypeFeature.CERTIFICATE) ? View.VISIBLE : View.GONE); mTncNotice.setVisibility(mVpnType.has(VpnTypeFeature.BYOD) ? View.VISIBLE : View.GONE); + mLocalIdWrap.setHelperText(getString(R.string.profile_local_id_hint_user)); if (mVpnType.has(VpnTypeFeature.CERTIFICATE)) { - mSelectUserId.setEnabled(false); if (mUserCertLoading != null) { ((TextView)mSelectUserCert.findViewById(android.R.id.text1)).setText(mUserCertLoading); @@ -471,8 +452,6 @@ public class VpnProfileDetailActivity extends AppCompatActivity ((TextView)mSelectUserCert.findViewById(android.R.id.text1)).setText(mUserCertEntry.getAlias()); ((TextView)mSelectUserCert.findViewById(android.R.id.text2)).setText(mUserCertEntry.getCertificate().getSubjectDN().toString()); mSelectUserIdAdapter.setCertificate(mUserCertEntry); - mSelectUserId.setSelection(mSelectUserIdAdapter.getPosition(mSelectedUserId)); - mSelectUserId.setEnabled(true); } else { @@ -480,6 +459,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity ((TextView)mSelectUserCert.findViewById(android.R.id.text2)).setText(R.string.profile_user_select_certificate); mSelectUserIdAdapter.setCertificate(null); } + mLocalIdWrap.setHelperText(getString(R.string.profile_local_id_hint_cert)); } } @@ -581,7 +561,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity mProfile.getIncludedSubnets() != null || mProfile.getExcludedSubnets() != null || mProfile.getSelectedAppsHandling() != SelectedAppsHandling.SELECTED_APPS_DISABLE || mProfile.getIkeProposal() != null || mProfile.getEspProposal() != null || - mProfile.getDnsServers() != null; + mProfile.getDnsServers() != null || mProfile.getLocalId() != null; } mShowAdvanced.setVisibility(!show ? View.VISIBLE : View.GONE); mAdvancedSettings.setVisibility(show ? View.VISIBLE : View.GONE); @@ -632,14 +612,14 @@ public class VpnProfileDetailActivity extends AppCompatActivity private boolean verifyInput() { boolean valid = true; - if (mGateway.getText().toString().trim().isEmpty()) + if (getString(mGateway) == null) { mGatewayWrap.setError(getString(R.string.alert_text_no_input_gateway)); valid = false; } if (mVpnType.has(VpnTypeFeature.USER_PASS)) { - if (mUsername.getText().toString().trim().isEmpty()) + if (getString(mUsername) == null) { mUsernameWrap.setError(getString(R.string.alert_text_no_input_username)); valid = false; @@ -705,27 +685,24 @@ public class VpnProfileDetailActivity extends AppCompatActivity private void updateProfileData() { /* the name is optional, we default to the gateway if none is given */ - String name = mName.getText().toString().trim(); - String gateway = mGateway.getText().toString().trim(); - mProfile.setName(name.isEmpty() ? gateway : name); + String name = getString(mName); + String gateway = getString(mGateway); + mProfile.setName(name == null ? gateway : name); mProfile.setGateway(gateway); mProfile.setVpnType(mVpnType); if (mVpnType.has(VpnTypeFeature.USER_PASS)) { - mProfile.setUsername(mUsername.getText().toString().trim()); - String password = mPassword.getText().toString().trim(); - password = password.isEmpty() ? null : password; - mProfile.setPassword(password); + mProfile.setUsername(getString(mUsername)); + mProfile.setPassword(getString(mPassword)); } if (mVpnType.has(VpnTypeFeature.CERTIFICATE)) { mProfile.setUserCertificateAlias(mUserCertEntry.getAlias()); - mProfile.setLocalId(mSelectedUserId); } String certAlias = mCheckAuto.isChecked() ? null : mCertEntry.getAlias(); mProfile.setCertificateAlias(certAlias); - String remote_id = mRemoteId.getText().toString().trim(); - mProfile.setRemoteId(remote_id.isEmpty() ? null : remote_id); + mProfile.setRemoteId(getString(mRemoteId)); + mProfile.setLocalId(getString(mLocalId)); mProfile.setMTU(getInteger(mMTU)); mProfile.setPort(getInteger(mPort)); mProfile.setNATKeepAlive(getInteger(mNATKeepalive)); @@ -736,22 +713,17 @@ public class VpnProfileDetailActivity extends AppCompatActivity flags |= mStrictRevocation.isChecked() ? VpnProfile.FLAGS_STRICT_REVOCATION : 0; flags |= mRsaPss.isChecked() ? VpnProfile.FLAGS_RSA_PSS : 0; mProfile.setFlags(flags); - String included = mIncludedSubnets.getText().toString().trim(); - mProfile.setIncludedSubnets(included.isEmpty() ? null : included); - String excluded = mExcludedSubnets.getText().toString().trim(); - mProfile.setExcludedSubnets(excluded.isEmpty() ? null : excluded); + mProfile.setIncludedSubnets(getString(mIncludedSubnets)); + mProfile.setExcludedSubnets(getString(mExcludedSubnets)); int st = 0; st |= mBlockIPv4.isChecked() ? VpnProfile.SPLIT_TUNNELING_BLOCK_IPV4 : 0; st |= mBlockIPv6.isChecked() ? VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6 : 0; mProfile.setSplitTunneling(st == 0 ? null : st); mProfile.setSelectedAppsHandling(mSelectedAppsHandling); mProfile.setSelectedApps(mSelectedApps); - String ike = mIkeProposal.getText().toString().trim(); - mProfile.setIkeProposal(ike.isEmpty() ? null : ike); - String esp = mEspProposal.getText().toString().trim(); - mProfile.setEspProposal(esp.isEmpty() ? null : esp); - String dns = mDnsServers.getText().toString().trim(); - mProfile.setDnsServers(dns.isEmpty() ? null : dns); + mProfile.setIkeProposal(getString(mIkeProposal)); + mProfile.setEspProposal(getString(mEspProposal)); + mProfile.setDnsServers(getString(mDnsServers)); } /** @@ -776,6 +748,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity mUsername.setText(mProfile.getUsername()); mPassword.setText(mProfile.getPassword()); mRemoteId.setText(mProfile.getRemoteId()); + mLocalId.setText(mProfile.getLocalId()); mMTU.setText(mProfile.getMTU() != null ? mProfile.getMTU().toString() : null); mPort.setText(mProfile.getPort() != null ? mProfile.getPort().toString() : null); mNATKeepalive.setText(mProfile.getNATKeepAlive() != null ? mProfile.getNATKeepAlive().toString() : null); @@ -812,12 +785,10 @@ public class VpnProfileDetailActivity extends AppCompatActivity /* check if the user selected a user certificate previously */ useralias = savedInstanceState == null ? useralias : savedInstanceState.getString(VpnProfileDataSource.KEY_USER_CERTIFICATE); - local_id = savedInstanceState == null ? local_id : savedInstanceState.getString(VpnProfileDataSource.KEY_LOCAL_ID); if (useralias != null) { UserCertificateLoader loader = new UserCertificateLoader(this, useralias); mUserCertLoading = useralias; - mSelectedUserId = local_id; loader.execute(); } @@ -846,6 +817,17 @@ public class VpnProfileDetailActivity extends AppCompatActivity } } + /** + * Get the string value in the given text box or null if empty + * + * @param view text box + */ + private String getString(EditText view) + { + String value = view.getText().toString().trim(); + return value.isEmpty() ? null : value; + } + /** * Get the integer value in the given text box or null if empty * @@ -943,7 +925,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity public void onClick(View v) { String useralias = mUserCertEntry != null ? mUserCertEntry.getAlias() : null; - KeyChain.choosePrivateKeyAlias(VpnProfileDetailActivity.this, this, new String[] { "RSA" }, null, null, -1, useralias); + KeyChain.choosePrivateKeyAlias(VpnProfileDetailActivity.this, this, null, null, null, -1, useralias); } @Override diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileImportActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileImportActivity.java index eae768378..33b396629 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileImportActivity.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileImportActivity.java @@ -505,6 +505,8 @@ public class VpnProfileImportActivity extends AppCompatActivity JSONObject local = obj.optJSONObject("local"); if (local != null) { + profile.setLocalId(local.optString("id", null)); + if (type.has(VpnTypeFeature.USER_PASS)) { profile.setUsername(local.optString("eap_id", null)); @@ -512,7 +514,6 @@ public class VpnProfileImportActivity extends AppCompatActivity if (type.has(VpnTypeFeature.CERTIFICATE)) { - profile.setLocalId(local.optString("id", null)); profile.PKCS12 = decodeBase64(local.optString("p12", null)); if (local.optBoolean("rsa-pss", false)) @@ -888,7 +889,7 @@ public class VpnProfileImportActivity extends AppCompatActivity { alias = getString(R.string.profile_cert_alias, mProfile.getName()); } - KeyChain.choosePrivateKeyAlias(VpnProfileImportActivity.this, this, new String[] { "RSA" }, null, null, -1, alias); + KeyChain.choosePrivateKeyAlias(VpnProfileImportActivity.this, this, null, null, null, -1, alias); } @Override diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/adapter/CertificateIdentitiesAdapter.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/adapter/CertificateIdentitiesAdapter.java index c8e3df38b..912f52441 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/adapter/CertificateIdentitiesAdapter.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/adapter/CertificateIdentitiesAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Tobias Brunner + * Copyright (C) 2016-2019 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -16,17 +16,10 @@ package org.strongswan.android.ui.adapter; import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; import android.widget.ArrayAdapter; -import android.widget.TextView; -import org.strongswan.android.R; import org.strongswan.android.security.TrustedCertificateEntry; -import java.util.List; - public class CertificateIdentitiesAdapter extends ArrayAdapter { TrustedCertificateEntry mCertificate; @@ -51,14 +44,8 @@ public class CertificateIdentitiesAdapter extends ArrayAdapter private void extractIdentities() { - if (mCertificate == null) + if (mCertificate != null) { - add(getContext().getString(R.string.profile_user_select_id_init)); - } - else - { - add(String.format(getContext().getString(R.string.profile_user_select_id_default), - mCertificate.getCertificate().getSubjectDN().getName())); addAll(mCertificate.getSubjectAltNames()); } } diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/adapter/VpnProfileAdapter.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/adapter/VpnProfileAdapter.java index f1ff1c6f8..d9201747a 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/adapter/VpnProfileAdapter.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/adapter/VpnProfileAdapter.java @@ -17,14 +17,6 @@ package org.strongswan.android.ui.adapter; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import org.strongswan.android.R; -import org.strongswan.android.data.VpnProfile; -import org.strongswan.android.data.VpnType.VpnTypeFeature; - import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -32,6 +24,14 @@ import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; +import org.strongswan.android.R; +import org.strongswan.android.data.VpnProfile; +import org.strongswan.android.data.VpnType.VpnTypeFeature; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + public class VpnProfileAdapter extends ArrayAdapter { private final int resource; @@ -74,7 +74,7 @@ public class VpnProfileAdapter extends ArrayAdapter profile.getLocalId() != null) { tv.setVisibility(View.VISIBLE); - tv.setText(getContext().getString(R.string.profile_user_select_id_label) + ": " + profile.getLocalId()); + tv.setText(getContext().getString(R.string.profile_local_id_label) + ": " + profile.getLocalId()); } else { diff --git a/src/frontends/android/app/src/main/res/layout/profile_detail_view.xml b/src/frontends/android/app/src/main/res/layout/profile_detail_view.xml index 0bdbc1d68..acab0b2f1 100644 --- a/src/frontends/android/app/src/main/res/layout/profile_detail_view.xml +++ b/src/frontends/android/app/src/main/res/layout/profile_detail_view.xml @@ -73,6 +73,7 @@ android:id="@+id/username_wrap" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="4dp" android:hint="@string/profile_username_label" > - - - - + android:hint="@string/profile_local_id_label" + app:helper_text="@string/profile_local_id_hint_user" > + android:completionThreshold="0" /> + + + + + + diff --git a/src/frontends/android/app/src/main/res/values-de/strings.xml b/src/frontends/android/app/src/main/res/values-de/strings.xml index f7fc36dc8..fcd14ea24 100644 --- a/src/frontends/android/app/src/main/res/values-de/strings.xml +++ b/src/frontends/android/app/src/main/res/values-de/strings.xml @@ -73,9 +73,6 @@ Benutzer-Zertifikat Benutzer-Zertifikat auswählen Wählen Sie ein bestimmtes Benutzer-Zertifikat - Benutzer-Identität - Wählen Sie zuerst ein Benutzer-Zertifikat - Standardwert (%1$s) CA-Zertifikat Automatisch wählen CA-Zertifikat auswählen @@ -85,8 +82,11 @@ Server-Identität Standardwert ist der konfigurierte Server. Eigene Werte werden explizit an den Server gesendet und während der Authentifizierung erzwungen Standardwert ist \"%1$s\". Eigene Werte werden explizit an den Server gesendet und während der Authentifizierung erzwungen + Client-Identität + Standardwert ist der konfigurierte Benutzername. Eigene Werte können verwendet werden, falls der Server diese erwartet/benötigt + Standardwert ist die Inhaber-Identität des Zertifkats. Eigene Werte können verwendet werden, falls der Server diese erwartet/benötigt. Zu beachten ist, dass diese üblicherweise vom Zertifikat bestätigt werden müssen (für die alternativen Identitäten des Zertifikats, falls vorhanden, wird eine Auto-Vervollständigung angeboten) DNS Server - Benutzerdefinierte DNS Server bei Verbindung zum VPN (mit Leerzeichen getrennt, z.B.. \"8.8.8.8 2001:4860:4860::8888\", standardmässig werden die vom VPN Server erhaltenen Server verwendet) + Benutzerdefinierte DNS Server bei Verbindung zum VPN (mit Leerzeichen getrennt, z.B.. \"8.8.8.8 2001:4860:4860::8888\"), standardmässig werden die vom VPN Server erhaltenen Server verwendet MTU des VPN Tunnel-Device Falls der Standardwert in einem bestimmten Netzwerk nicht geeignet ist Server Port diff --git a/src/frontends/android/app/src/main/res/values-pl/strings.xml b/src/frontends/android/app/src/main/res/values-pl/strings.xml index b202b6706..6f4716ba8 100644 --- a/src/frontends/android/app/src/main/res/values-pl/strings.xml +++ b/src/frontends/android/app/src/main/res/values-pl/strings.xml @@ -73,9 +73,6 @@ Certyfikat użytkownika Wybierz certyfikat użytkownika >Wybierz określony certyfikat użytkownika - User identity - Select a certificate first - Default (%1$s) Certyfikat CA Wybierz automatycznie Wybierz certyfikat CA @@ -85,8 +82,11 @@ Server identity Defaults to the configured server. Custom values are explicitly sent to the server and enforced during authentication Defaults to \"%1$s\". Custom values are explicitly sent to the server and enforced during authentication + Client identity + Defaults to the configured username. Custom values may be used if expected/required by the server + Defaults to the certificate\'s subject identity. Custom values may be used if expected/required by the server. Note that these usually must be confirmed by the certificate (auto-completion is provided for the certificate\'s alternative identities, if any) DNS servers - Custom DNS servers to use when connected to the VPN (separated by spaces, e.g. \"8.8.8.8 2001:4860:4860::8888\", defaults to those received from the VPN server) + Custom DNS servers to use when connected to the VPN (separated by spaces, e.g. \"8.8.8.8 2001:4860:4860::8888\"), defaults to those received from the VPN server MTU of the VPN tunnel device In case the default value is unsuitable for a particular network Server port diff --git a/src/frontends/android/app/src/main/res/values-ru/strings.xml b/src/frontends/android/app/src/main/res/values-ru/strings.xml index 1f81587dc..5def66df8 100644 --- a/src/frontends/android/app/src/main/res/values-ru/strings.xml +++ b/src/frontends/android/app/src/main/res/values-ru/strings.xml @@ -70,9 +70,6 @@ Сертификат пользователя Выбрать сертификат пользователя Выбрать сертификат пользователя - User identity - Select a certificate first - Default (%1$s) Сертификат CA Выбрать автоматически Выбрать сертификат CA @@ -82,8 +79,11 @@ Server identity Defaults to the configured server. Custom values are explicitly sent to the server and enforced during authentication Defaults to \"%1$s\". Custom values are explicitly sent to the server and enforced during authentication + Client identity + Defaults to the configured username. Custom values may be used if expected/required by the server + Defaults to the certificate\'s subject identity. Custom values may be used if expected/required by the server. Note that these usually must be confirmed by the certificate (auto-completion is provided for the certificate\'s alternative identities, if any) DNS servers - Custom DNS servers to use when connected to the VPN (separated by spaces, e.g. \"8.8.8.8 2001:4860:4860::8888\", defaults to those received from the VPN server) + Custom DNS servers to use when connected to the VPN (separated by spaces, e.g. \"8.8.8.8 2001:4860:4860::8888\"), defaults to those received from the VPN server MTU of the VPN tunnel device In case the default value is unsuitable for a particular network Server port diff --git a/src/frontends/android/app/src/main/res/values-ua/strings.xml b/src/frontends/android/app/src/main/res/values-ua/strings.xml index 95fdd428a..4920aa238 100644 --- a/src/frontends/android/app/src/main/res/values-ua/strings.xml +++ b/src/frontends/android/app/src/main/res/values-ua/strings.xml @@ -71,9 +71,6 @@ Сертифікат користувача Виберіть сертифікат користувача Вибрати спеціальний сертифікат користувача - User identity - Select a certificate first - Default (%1$s) Сертифікат CA Вибрати автоматично Вибрати сертифікат CA @@ -83,8 +80,11 @@ Server identity Defaults to the configured server. Custom values are explicitly sent to the server and enforced during authentication Defaults to \"%1$s\". Custom values are explicitly sent to the server and enforced during authentication + Client identity + Defaults to the configured username. Custom values may be used if expected/required by the server + Defaults to the certificate\'s subject identity. Custom values may be used if expected/required by the server. Note that these usually must be confirmed by the certificate (auto-completion is provided for the certificate\'s alternative identities, if any) DNS servers - Custom DNS servers to use when connected to the VPN (separated by spaces, e.g. \"8.8.8.8 2001:4860:4860::8888\", defaults to those received from the VPN server) + Custom DNS servers to use when connected to the VPN (separated by spaces, e.g. \"8.8.8.8 2001:4860:4860::8888\"), defaults to those received from the VPN server MTU of the VPN tunnel device In case the default value is unsuitable for a particular network Server port diff --git a/src/frontends/android/app/src/main/res/values-zh-rCN/strings.xml b/src/frontends/android/app/src/main/res/values-zh-rCN/strings.xml index 006ad5359..3408f5f55 100644 --- a/src/frontends/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/frontends/android/app/src/main/res/values-zh-rCN/strings.xml @@ -70,9 +70,6 @@ 用户证书 选择用户证书 选择指定的用户证书 - 用户ID - 首先选择一个证书 - 默认(%1$s) CA证书 自动选择 选择CA证书 @@ -82,6 +79,11 @@ 服务器ID 默认为已配置的服务器地址。自义定值将在鉴权期间被显式地发送至服务器 默认为 \"%1$s\"。自义定值将在鉴权期间被显式地发送至服务器 + Client identity + Defaults to the configured username. Custom values may be used if expected/required by the server + Defaults to the certificate\'s subject identity. Custom values may be used if expected/required by the server. Note that these usually must be confirmed by the certificate (auto-completion is provided for the certificate\'s alternative identities, if any) + DNS servers + Custom DNS servers to use when connected to the VPN (separated by spaces, e.g. \"8.8.8.8 2001:4860:4860::8888\"), defaults to those received from the VPN server VPN隧道设备的MTU值 假如在某一网络下默认值不合适 服务器端口 diff --git a/src/frontends/android/app/src/main/res/values-zh-rTW/strings.xml b/src/frontends/android/app/src/main/res/values-zh-rTW/strings.xml index 12666ca55..e3d7f0361 100644 --- a/src/frontends/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/frontends/android/app/src/main/res/values-zh-rTW/strings.xml @@ -70,9 +70,6 @@ 用戶憑證 選擇用戶憑證 選擇指定的用戶憑證 - 用戶帳號 - 請先選擇一個憑證 - 預設(%1$s) CA憑證 自動選擇 選擇CA憑證 @@ -82,8 +79,11 @@ 伺服器ID 預設為已設定的伺服器位置。自訂值會在授權期間送到伺服器 預設為 \"%1$s\"。自訂值會在授權期間送到伺服器 + Client identity + Defaults to the configured username. Custom values may be used if expected/required by the server + Defaults to the certificate\'s subject identity. Custom values may be used if expected/required by the server. Note that these usually must be confirmed by the certificate (auto-completion is provided for the certificate\'s alternative identities, if any) DNS servers - Custom DNS servers to use when connected to the VPN (separated by spaces, e.g. \"8.8.8.8 2001:4860:4860::8888\", defaults to those received from the VPN server) + Custom DNS servers to use when connected to the VPN (separated by spaces, e.g. \"8.8.8.8 2001:4860:4860::8888\"), defaults to those received from the VPN server VPN通道裝置的MTU值 如果在某個網路下預設值不適合 伺服器Port diff --git a/src/frontends/android/app/src/main/res/values/strings.xml b/src/frontends/android/app/src/main/res/values/strings.xml index e86e84b5a..4d9fd879f 100644 --- a/src/frontends/android/app/src/main/res/values/strings.xml +++ b/src/frontends/android/app/src/main/res/values/strings.xml @@ -73,9 +73,6 @@ User certificate Select user certificate Select a specific user certificate - User identity - Select a certificate first - Default (%1$s) CA certificate Select automatically Select CA certificate @@ -85,8 +82,11 @@ Server identity Defaults to the configured server. Custom values are explicitly sent to the server and enforced during authentication Defaults to \"%1$s\". Custom values are explicitly sent to the server and enforced during authentication + Client identity + Defaults to the configured username. Custom values may be used if expected/required by the server + Defaults to the certificate\'s subject identity. Custom values may be used if expected/required by the server. Note that these usually must be confirmed by the certificate (auto-completion is provided for the certificate\'s alternative identities, if any) DNS servers - Custom DNS servers to use when connected to the VPN (separated by spaces, e.g. \"8.8.8.8 2001:4860:4860::8888\", defaults to those received from the VPN server) + Custom DNS servers to use when connected to the VPN (separated by spaces, e.g. \"8.8.8.8 2001:4860:4860::8888\"), defaults to those received from the VPN server MTU of the VPN tunnel device In case the default value is unsuitable for a particular network Server port diff --git a/src/frontends/android/build.gradle b/src/frontends/android/build.gradle index f5a685070..5880d1696 100644 --- a/src/frontends/android/build.gradle +++ b/src/frontends/android/build.gradle @@ -4,7 +4,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.4.2' + classpath 'com.android.tools.build:gradle:3.5.1' } } diff --git a/src/frontends/android/gradle/wrapper/gradle-wrapper.properties b/src/frontends/android/gradle/wrapper/gradle-wrapper.properties index 54bc74adb..558ba36a3 100644 --- a/src/frontends/android/gradle/wrapper/gradle-wrapper.properties +++ b/src/frontends/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Aug 13 13:47:52 CEST 2019 +#Mon Oct 07 16:41:25 CEST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/src/libcharon/sa/ikev2/tasks/ike_delete.c b/src/libcharon/sa/ikev2/tasks/ike_delete.c index fd36b144a..49cd66370 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_delete.c +++ b/src/libcharon/sa/ikev2/tasks/ike_delete.c @@ -168,6 +168,33 @@ METHOD(task_t, process_r, status_t, return NEED_MORE; } +/** + * Check if we are currently deleting this IKE_SA in a break-before-make reauth. + */ +static bool is_reauthenticating(private_ike_delete_t *this) +{ + enumerator_t *tasks; + task_t *task; + + if (!this->ike_sa->has_condition(this->ike_sa, COND_REAUTHENTICATING)) + { + return FALSE; + } + + tasks = this->ike_sa->create_task_enumerator(this->ike_sa, + TASK_QUEUE_ACTIVE); + while (tasks->enumerate(tasks, &task)) + { + if (task->get_type(task) == TASK_IKE_REAUTH) + { + tasks->destroy(tasks); + return TRUE; + } + } + tasks->destroy(tasks); + return FALSE; +} + METHOD(task_t, build_r, status_t, private_ike_delete_t *this, message_t *message) { @@ -177,6 +204,18 @@ METHOD(task_t, build_r, status_t, { /* invoke ike_down() hook if SA has not been rekeyed */ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); } + + /* if we are currently deleting this IKE_SA due to a break-before-make + * reauthentication, make sure to not just silently destroy the SA if + * the peer concurrently deletes it */ + if (is_reauthenticating(this)) + { + if (this->ike_sa->reestablish(this->ike_sa) != SUCCESS) + { + DBG1(DBG_IKE, "reauthenticating IKE_SA failed"); + } + } + /* completed, delete IKE_SA by returning DESTROY_ME */ return DESTROY_ME; }