diff --git a/src/frontends/android/app/build.gradle b/src/frontends/android/app/build.gradle index cab3a6c6d..f513e52be 100644 --- a/src/frontends/android/app/build.gradle +++ b/src/frontends/android/app/build.gradle @@ -9,8 +9,8 @@ android { minSdkVersion 21 targetSdkVersion 34 - versionCode 84 - versionName "2.5.2" + versionCode 87 + versionName "2.5.3" externalNativeBuild { ndkBuild { @@ -19,7 +19,7 @@ android { } } - ndkVersion "26.1.10909125" + ndkVersion "27.2.12479018" externalNativeBuild { ndkBuild { diff --git a/src/frontends/android/app/src/main/AndroidManifest.xml b/src/frontends/android/app/src/main/AndroidManifest.xml index a5e6aabc2..51c6ff89e 100644 --- a/src/frontends/android/app/src/main/AndroidManifest.xml +++ b/src/frontends/android/app/src/main/AndroidManifest.xml @@ -37,6 +37,7 @@ android:label="@string/app_name" android:theme="@style/ApplicationTheme" android:networkSecurityConfig="@xml/network_security_config" + android:enableOnBackInvokedCallback="true" android:allowBackup="false" > getBundleArrayListCompat(final Bundle bundle, final String key) { diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/data/ManagedVpnProfile.java b/src/frontends/android/app/src/main/java/org/strongswan/android/data/ManagedVpnProfile.java index 054dde19f..30943aa6b 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/data/ManagedVpnProfile.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/data/ManagedVpnProfile.java @@ -68,9 +68,9 @@ public class ManagedVpnProfile extends VpnProfile setMTU(getInt(bundle, VpnProfileDataSource.KEY_MTU, Constants.MTU_MIN, Constants.MTU_MAX)); setNATKeepAlive(getInt(bundle, VpnProfileDataSource.KEY_NAT_KEEPALIVE, Constants.NAT_KEEPALIVE_MIN, Constants.NAT_KEEPALIVE_MAX)); - setIkeProposal(bundle.getString(VpnProfileDataSource.KEY_IKE_PROPOSAL)); - setEspProposal(bundle.getString(VpnProfileDataSource.KEY_ESP_PROPOSAL)); - setDnsServers(bundle.getString(VpnProfileDataSource.KEY_DNS_SERVERS)); + setIkeProposal(getString(bundle, VpnProfileDataSource.KEY_IKE_PROPOSAL)); + setEspProposal(getString(bundle, VpnProfileDataSource.KEY_ESP_PROPOSAL)); + setDnsServers(getString(bundle, VpnProfileDataSource.KEY_DNS_SERVERS)); flags = addPositiveFlag(flags, bundle, KEY_TRANSPORT_IPV6_FLAG, VpnProfile.FLAGS_IPv6_TRANSPORT); final Bundle splitTunneling = bundle.getBundle(VpnProfileDataSource.KEY_SPLIT_TUNNELING); @@ -79,8 +79,8 @@ public class ManagedVpnProfile extends VpnProfile splitFlags = addPositiveFlag(splitFlags, splitTunneling, KEY_SPLIT_TUNNELLING_BLOCK_IPV4_FLAG, VpnProfile.SPLIT_TUNNELING_BLOCK_IPV4); splitFlags = addPositiveFlag(splitFlags, splitTunneling, KEY_SPLIT_TUNNELLING_BLOCK_IPV6_FLAG, VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6); - setExcludedSubnets(splitTunneling.getString(VpnProfileDataSource.KEY_EXCLUDED_SUBNETS)); - setIncludedSubnets(splitTunneling.getString(VpnProfileDataSource.KEY_INCLUDED_SUBNETS)); + setExcludedSubnets(getString(splitTunneling, VpnProfileDataSource.KEY_EXCLUDED_SUBNETS)); + setIncludedSubnets(getString(splitTunneling, VpnProfileDataSource.KEY_INCLUDED_SUBNETS)); } setSplitTunneling(splitFlags); @@ -110,7 +110,7 @@ public class ManagedVpnProfile extends VpnProfile setGateway(remote.getString(VpnProfileDataSource.KEY_GATEWAY)); setPort(getInt(remote, VpnProfileDataSource.KEY_PORT, 1, 65_535)); - setRemoteId(remote.getString(VpnProfileDataSource.KEY_REMOTE_ID)); + setRemoteId(getString(remote, VpnProfileDataSource.KEY_REMOTE_ID)); final String certificateData = remote.getString(VpnProfileDataSource.KEY_CERTIFICATE); if (!TextUtils.isEmpty(certificateData)) @@ -133,8 +133,9 @@ public class ManagedVpnProfile extends VpnProfile return flags; } - setLocalId(local.getString(VpnProfileDataSource.KEY_LOCAL_ID)); - setUsername(local.getString(VpnProfileDataSource.KEY_USERNAME)); + setLocalId(getString(local, VpnProfileDataSource.KEY_LOCAL_ID)); + setUsername(getString(local, VpnProfileDataSource.KEY_USERNAME)); + setPassword(getString(local, VpnProfileDataSource.KEY_PASSWORD)); final String userCertificateData = local.getString(VpnProfileDataSource.KEY_USER_CERTIFICATE); final String userCertificatePassword = local.getString(VpnProfileDataSource.KEY_USER_CERTIFICATE_PASSWORD, ""); @@ -154,6 +155,12 @@ public class ManagedVpnProfile extends VpnProfile return value < min || value > max ? null : value; } + private static String getString(final Bundle bundle, final String key) + { + final String value = bundle.getString(key); + return TextUtils.isEmpty(value) ? null : value; + } + private static int addPositiveFlag(int flags, Bundle bundle, String key, int flag) { if (bundle.getBoolean(key)) diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileManagedDataSource.java b/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileManagedDataSource.java index 414d5bc4e..0f6ec6292 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileManagedDataSource.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileManagedDataSource.java @@ -1,4 +1,5 @@ /* + * Copyright (C) 2025 Tobias Brunner * Copyright (C) 2023 Relution GmbH * * Copyright (C) secunet Security Networks AG @@ -75,17 +76,14 @@ public class VpnProfileManagedDataSource implements VpnProfileDataSource @Override public boolean updateVpnProfile(VpnProfile profile) { - final VpnProfile existingProfile = getVpnProfile(profile.getUUID()); - if (existingProfile == null) + final VpnProfile managedProfile = mManagedConfigurationService.getManagedProfiles().get(profile.getUUID().toString()); + if (managedProfile == null) { return false; } - final String password = profile.getPassword(); - existingProfile.setPassword(password); - final SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putString(profile.getUUID().toString(), password); + editor.putString(profile.getUUID().toString(), profile.getPassword()); return editor.commit(); } @@ -95,10 +93,28 @@ public class VpnProfileManagedDataSource implements VpnProfileDataSource return false; } + /** + * Clone and prepare the given managed profile before handing it out. + * @param managedProfile profile to prepare + */ + private VpnProfile prepareVpnProfile(VpnProfile managedProfile) + { + final String password = mSharedPreferences.getString(managedProfile.getUUID().toString(), managedProfile.getPassword()); + final VpnProfile vpnProfile = managedProfile.clone(); + vpnProfile.setPassword(password); + vpnProfile.setDataSource(this); + return vpnProfile; + } + @Override public VpnProfile getVpnProfile(UUID uuid) { - return mManagedConfigurationService.getManagedProfiles().get(uuid.toString()); + final VpnProfile managedProfile = mManagedConfigurationService.getManagedProfiles().get(uuid.toString()); + if (managedProfile != null) + { + return prepareVpnProfile(managedProfile); + } + return null; } @Override @@ -106,12 +122,9 @@ public class VpnProfileManagedDataSource implements VpnProfileDataSource { final Map managedVpnProfiles = mManagedConfigurationService.getManagedProfiles(); final List vpnProfiles = new ArrayList<>(); - for (final VpnProfile vpnProfile : managedVpnProfiles.values()) + for (final VpnProfile managedProfile : managedVpnProfiles.values()) { - final String password = mSharedPreferences.getString(vpnProfile.getUUID().toString(), vpnProfile.getPassword()); - vpnProfile.setPassword(password); - vpnProfile.setDataSource(this); - vpnProfiles.add(vpnProfile); + vpnProfiles.add(prepareVpnProfile(managedProfile)); } return vpnProfiles; } diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java index 03e59f7ee..314678ede 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java @@ -399,11 +399,24 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe public void run() { mShowNotification = false; - stopForeground(true); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) + { + stopForegroundCompat(); + } + else + { + stopForeground(STOP_FOREGROUND_REMOVE); + } } }); } + @SuppressWarnings("deprecation") + private void stopForegroundCompat() + { + stopForeground(true); + } + /** * Create a notification channel for Android 8+ */ diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionFragment.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionFragment.java index ea33a14e6..c26741504 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionFragment.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionFragment.java @@ -16,6 +16,7 @@ package org.strongswan.android.ui; +import android.os.Build; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -58,7 +59,14 @@ public class RemediationInstructionFragment extends ListFragment if (savedInstanceState != null) { - mInstruction = savedInstanceState.getParcelable(ARG_REMEDIATION_INSTRUCTION); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) + { + mInstruction = getInstructionCompat(savedInstanceState); + } + else + { + mInstruction = savedInstanceState.getParcelable(ARG_REMEDIATION_INSTRUCTION, RemediationInstruction.class); + } } /* show dividers only between list items */ getListView().setHeaderDividersEnabled(false); @@ -85,7 +93,14 @@ public class RemediationInstructionFragment extends ListFragment Bundle args = getArguments(); if (args != null) { - mInstruction = args.getParcelable(ARG_REMEDIATION_INSTRUCTION); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) + { + mInstruction = getInstructionCompat(args); + } + else + { + mInstruction = args.getParcelable(ARG_REMEDIATION_INSTRUCTION, RemediationInstruction.class); + } } updateView(mInstruction); } @@ -117,4 +132,10 @@ public class RemediationInstructionFragment extends ListFragment setListAdapter(null); } } + + @SuppressWarnings("deprecation") + private static RemediationInstruction getInstructionCompat(Bundle bundle) + { + return bundle.getParcelable(ARG_REMEDIATION_INSTRUCTION); + } } diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionsActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionsActivity.java index 4d8f2f1a3..d1de55214 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionsActivity.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionsActivity.java @@ -43,7 +43,16 @@ public class RemediationInstructionsActivity extends AppCompatActivity implement if (frag != null) { /* two-pane layout, update fragment */ Bundle extras = getIntent().getExtras(); - ArrayList list = extras.getParcelableArrayList(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS); + ArrayList list = null; + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.TIRAMISU) + { + list = RemediationInstructionsFragment.getInstructionsCompat(extras); + } + else + { + list = extras.getParcelableArrayList(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS, + RemediationInstruction.class); + } frag.updateView(list); } else diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionsFragment.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionsFragment.java index 0f74bfd41..937f32c0d 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionsFragment.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionsFragment.java @@ -17,6 +17,7 @@ package org.strongswan.android.ui; import android.content.Context; +import android.os.Build; import android.os.Bundle; import android.view.View; import android.widget.ListView; @@ -55,7 +56,14 @@ public class RemediationInstructionsFragment extends ListFragment if (savedInstanceState != null) { - mInstructions = savedInstanceState.getParcelableArrayList(EXTRA_REMEDIATION_INSTRUCTIONS); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) + { + mInstructions = getInstructionsCompat(savedInstanceState); + } + else + { + mInstructions = savedInstanceState.getParcelableArrayList(EXTRA_REMEDIATION_INSTRUCTIONS, RemediationInstruction.class); + } mCurrentPosition = savedInstanceState.getInt(KEY_POSITION); } } @@ -93,7 +101,14 @@ public class RemediationInstructionsFragment extends ListFragment Bundle args = getArguments(); if (mInstructions == null && args != null) { - mInstructions = args.getParcelableArrayList(EXTRA_REMEDIATION_INSTRUCTIONS); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) + { + mInstructions = getInstructionsCompat(args); + } + else + { + mInstructions = args.getParcelableArrayList(EXTRA_REMEDIATION_INSTRUCTIONS, RemediationInstruction.class); + } } updateView(mInstructions); @@ -123,4 +138,10 @@ public class RemediationInstructionsFragment extends ListFragment mInstructions = instructions; mAdapter.setData(mInstructions); } + + @SuppressWarnings("deprecation") + public static ArrayList getInstructionsCompat(Bundle bundle) + { + return bundle.getParcelableArrayList(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS); + } } diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SelectedApplicationsActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SelectedApplicationsActivity.java index d437e3aa3..d1b66e4ee 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SelectedApplicationsActivity.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SelectedApplicationsActivity.java @@ -22,6 +22,7 @@ import android.view.MenuItem; import org.strongswan.android.data.VpnProfileDataSource; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; @@ -40,6 +41,16 @@ public class SelectedApplicationsActivity extends AppCompatActivity ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); + getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) + { + @Override + public void handleOnBackPressed() + { + prepareResult(); + finish(); + } + }); + FragmentManager fm = getSupportFragmentManager(); mApps = (SelectedApplicationsListFragment)fm.findFragmentByTag(LIST_TAG); if (mApps == null) @@ -62,13 +73,6 @@ public class SelectedApplicationsActivity extends AppCompatActivity return super.onOptionsItemSelected(item); } - @Override - public void onBackPressed() - { - prepareResult(); - super.onBackPressed(); - } - private void prepareResult() { Intent data = new Intent(); diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SelectedApplicationsListFragment.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SelectedApplicationsListFragment.java index 5ef78b295..89b581530 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SelectedApplicationsListFragment.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SelectedApplicationsListFragment.java @@ -44,12 +44,13 @@ import java.util.TreeSet; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.SearchView; +import androidx.core.view.MenuProvider; import androidx.fragment.app.ListFragment; import androidx.loader.app.LoaderManager; import androidx.loader.content.AsyncTaskLoader; import androidx.loader.content.Loader; -public class SelectedApplicationsListFragment extends ListFragment implements LoaderManager.LoaderCallbacks, List>>, SearchView.OnQueryTextListener +public class SelectedApplicationsListFragment extends ListFragment implements MenuProvider, LoaderManager.LoaderCallbacks, List>>, SearchView.OnQueryTextListener { private SelectedApplicationsAdapter mAdapter; private SortedSet mSelection; @@ -58,7 +59,7 @@ public class SelectedApplicationsListFragment extends ListFragment implements Lo public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - setHasOptionsMenu(true); + requireActivity().addMenuProvider(this, getViewLifecycleOwner()); final boolean readOnly = getActivity().getIntent().getBooleanExtra(VpnProfileDataSource.KEY_READ_ONLY, false); getListView().setChoiceMode(readOnly ? ListView.CHOICE_MODE_NONE : ListView.CHOICE_MODE_MULTIPLE); @@ -134,17 +135,21 @@ public class SelectedApplicationsListFragment extends ListFragment implements Lo } @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) + public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) { MenuItem item = menu.add(R.string.search); item.setIcon(android.R.drawable.ic_menu_search); - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); SearchView sv = new SearchView(getActivity()); sv.setOnQueryTextListener(this); item.setActionView(sv); + } - super.onCreateOptionsMenu(menu, inflater); + @Override + public boolean onMenuItemSelected(@NonNull MenuItem menuItem) + { + return false; } @Override diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificateImportActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificateImportActivity.java index 60e57b03b..322e21e2c 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificateImportActivity.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificateImportActivity.java @@ -21,6 +21,7 @@ import android.content.ActivityNotFoundException; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.widget.Toast; @@ -191,7 +192,14 @@ public class TrustedCertificateImportActivity extends AppCompatActivity { final X509Certificate certificate; - certificate = (X509Certificate)getArguments().getSerializable(VpnProfileDataSource.KEY_CERTIFICATE); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) + { + certificate = getCertificateCompat(getArguments()); + } + else + { + certificate = getArguments().getSerializable(VpnProfileDataSource.KEY_CERTIFICATE, X509Certificate.class); + } return new AlertDialog.Builder(getActivity()) .setIcon(R.mipmap.ic_app) @@ -230,5 +238,11 @@ public class TrustedCertificateImportActivity extends AppCompatActivity { getActivity().finish(); } + + @SuppressWarnings("deprecation") + private static X509Certificate getCertificateCompat(Bundle bundle) + { + return (X509Certificate)bundle.getSerializable(VpnProfileDataSource.KEY_CERTIFICATE); + } } } diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificateListFragment.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificateListFragment.java index 1ceba87f7..19f38f6bb 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificateListFragment.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificateListFragment.java @@ -17,6 +17,7 @@ package org.strongswan.android.ui; import android.content.Context; +import android.os.Build; import android.os.Bundle; import android.text.TextUtils; import android.view.Menu; @@ -44,13 +45,15 @@ import java.util.Map.Entry; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.view.MenuProvider; import androidx.fragment.app.ListFragment; +import androidx.lifecycle.Lifecycle; import androidx.loader.app.LoaderManager; import androidx.loader.app.LoaderManager.LoaderCallbacks; import androidx.loader.content.AsyncTaskLoader; import androidx.loader.content.Loader; -public class TrustedCertificateListFragment extends ListFragment implements LoaderCallbacks>, OnQueryTextListener +public class TrustedCertificateListFragment extends ListFragment implements MenuProvider, LoaderCallbacks>, OnQueryTextListener { public static final String EXTRA_CERTIFICATE_SOURCE = "certificate_source"; private OnTrustedCertificateSelectedListener mListener; @@ -69,7 +72,7 @@ public class TrustedCertificateListFragment extends ListFragment implements Load public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - setHasOptionsMenu(true); + requireActivity().addMenuProvider(this, getViewLifecycleOwner(), Lifecycle.State.RESUMED); setEmptyText(getString(R.string.no_certificates)); @@ -81,7 +84,14 @@ public class TrustedCertificateListFragment extends ListFragment implements Load Bundle arguments = getArguments(); if (arguments != null) { - mSource = (TrustedCertificateSource)arguments.getSerializable(EXTRA_CERTIFICATE_SOURCE); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) + { + mSource = getCertificateSourceCompat(arguments); + } + else + { + mSource = arguments.getSerializable(EXTRA_CERTIFICATE_SOURCE, TrustedCertificateSource.class); + } } LoaderManager.getInstance(this).initLoader(0, null, this); @@ -105,17 +115,23 @@ public class TrustedCertificateListFragment extends ListFragment implements Load } @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) + public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) { MenuItem item = menu.add(R.string.search); item.setIcon(android.R.drawable.ic_menu_search); - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); SearchView sv = new SearchView(getActivity()); sv.setOnQueryTextListener(this); item.setActionView(sv); } + @Override + public boolean onMenuItemSelected(@NonNull MenuItem menuItem) + { + return false; + } + @Override public boolean onQueryTextSubmit(String query) { /* already handled when the text changes */ @@ -260,4 +276,10 @@ public class TrustedCertificateListFragment extends ListFragment implements Load } } } + + @SuppressWarnings("deprecation") + private static TrustedCertificateSource getCertificateSourceCompat(Bundle bundle) + { + return (TrustedCertificateSource)bundle.getSerializable(EXTRA_CERTIFICATE_SOURCE); + } } 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 f49d84bc8..08565d67b 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 @@ -21,6 +21,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.security.KeyChain; import android.security.KeyChainAliasCallback; @@ -98,6 +99,7 @@ public class VpnProfileImportActivity extends AppCompatActivity private boolean mHideImport; private androidx.core.widget.ContentLoadingProgressBar mProgressBar; private TextView mExistsWarning; + private TextView mSharedSecretWarning; private ViewGroup mBasicDataGroup; private TextView mName; private TextView mGateway; @@ -139,6 +141,19 @@ public class VpnProfileImportActivity extends AppCompatActivity { @Override public Loader onCreateLoader(int id, Bundle args) + { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) + { + return createCompat(args); + } + else + { + return new ProfileLoader(VpnProfileImportActivity.this, args.getParcelable(PROFILE_URI, Uri.class)); + } + } + + @SuppressWarnings("deprecation") + public Loader createCompat(Bundle args) { return new ProfileLoader(VpnProfileImportActivity.this, args.getParcelable(PROFILE_URI)); } @@ -192,6 +207,7 @@ public class VpnProfileImportActivity extends AppCompatActivity mProgressBar = findViewById(R.id.progress_bar); mExistsWarning = findViewById(R.id.exists_warning); + mSharedSecretWarning = findViewById(R.id.shared_secret_warning); mBasicDataGroup = findViewById(R.id.basic_data_group); mName = findViewById(R.id.name); mGateway = findViewById(R.id.gateway); @@ -210,6 +226,7 @@ public class VpnProfileImportActivity extends AppCompatActivity mRemoteCert = findViewById(R.id.remote_certificate); mExistsWarning.setVisibility(View.GONE); + mSharedSecretWarning.setVisibility(View.GONE); mBasicDataGroup.setVisibility(View.GONE); mUsernamePassword.setVisibility(View.GONE); mUserCertificate.setVisibility(View.GONE); @@ -386,10 +403,16 @@ public class VpnProfileImportActivity extends AppCompatActivity if (mProfile.getVpnType().has(VpnTypeFeature.USER_PASS)) { mUsername.setText(mProfile.getUsername()); - if (mProfile.getUsername() != null && !mProfile.getUsername().isEmpty()) + if (!TextUtils.isEmpty(mProfile.getUsername())) { mUsername.setEnabled(false); } + mPassword.setText(mProfile.getPassword()); + if (!TextUtils.isEmpty(mProfile.getPassword())) + { + mPassword.setEnabled(false); + mSharedSecretWarning.setVisibility(View.VISIBLE); + } } mUserCertificate.setVisibility(mProfile.getVpnType().has(VpnTypeFeature.CERTIFICATE) ? View.VISIBLE : View.GONE); @@ -509,6 +532,7 @@ public class VpnProfileImportActivity extends AppCompatActivity if (type.has(VpnTypeFeature.USER_PASS)) { profile.setUsername(local.optString("eap_id", null)); + profile.setPassword(local.optString("shared_secret", null)); } if (type.has(VpnTypeFeature.CERTIFICATE)) diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java index 6a22fdf5b..9b25785f1 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java @@ -57,10 +57,13 @@ import java.util.Objects; import java.util.Set; import java.util.UUID; +import androidx.annotation.NonNull; +import androidx.core.view.MenuProvider; import androidx.fragment.app.Fragment; +import androidx.lifecycle.Lifecycle; import androidx.localbroadcastmanager.content.LocalBroadcastManager; -public class VpnProfileListFragment extends Fragment +public class VpnProfileListFragment extends Fragment implements MenuProvider { private static final String SELECTED_KEY = "SELECTED"; @@ -148,6 +151,7 @@ public class VpnProfileListFragment extends Fragment if (!mReadOnly) { + requireActivity().addMenuProvider(this, getViewLifecycleOwner()); mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); mListView.setMultiChoiceModeListener(mVpnProfileSelected); } @@ -167,8 +171,6 @@ public class VpnProfileListFragment extends Fragment if (!mReadOnly) { - setHasOptionsMenu(true); - ArrayList selected = null; if (savedInstanceState != null) { @@ -218,13 +220,13 @@ public class VpnProfileListFragment extends Fragment } @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) + public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) { - inflater.inflate(R.menu.profile_list, menu); + menuInflater.inflate(R.menu.profile_list, menu); } @Override - public void onPrepareOptionsMenu(Menu menu) + public void onPrepareMenu(@NonNull Menu menu) { final MenuItem addProfile = menu.findItem(R.id.add_profile); if (addProfile != null) @@ -236,16 +238,16 @@ public class VpnProfileListFragment extends Fragment } @Override - public boolean onOptionsItemSelected(MenuItem item) + public boolean onMenuItemSelected(@NonNull MenuItem menuItem) { - if (item.getItemId() == R.id.add_profile) + if (menuItem.getItemId() == R.id.add_profile) { Intent connectionIntent = new Intent(getActivity(), VpnProfileDetailActivity.class); startActivity(connectionIntent); return true; } - return super.onOptionsItemSelected(item); + return false; } private final OnItemClickListener mVpnProfileClicked = new OnItemClickListener() diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnTileService.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnTileService.java index 05c3e2da9..6f95a626a 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnTileService.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnTileService.java @@ -187,7 +187,7 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt } else { - startActivityAndCollapse(intent); + startActivityAndCollapseCompat(intent); } } else @@ -214,10 +214,16 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt } else { - startActivityAndCollapse(intent); + startActivityAndCollapseCompat(intent); } } + @SuppressWarnings("deprecation") + private void startActivityAndCollapseCompat(Intent intent) + { + startActivityAndCollapse(intent); + } + @Override public void stateChanged() { diff --git a/src/frontends/android/app/src/main/jni/Application.mk b/src/frontends/android/app/src/main/jni/Application.mk index 2133d20c6..a71cd74c9 100644 --- a/src/frontends/android/app/src/main/jni/Application.mk +++ b/src/frontends/android/app/src/main/jni/Application.mk @@ -1 +1,2 @@ APP_PLATFORM := android-21 +APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c b/src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c index 89868a710..12ac01727 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c @@ -820,6 +820,7 @@ JNI_METHOD_P(org_strongswan_android_utils, Utils, parseInetAddressBytes, jbyteAr host = host_create_from_string(str, 0); if (!host) { + library_deinit(); free(str); return NULL; } diff --git a/src/frontends/android/app/src/main/play/release-notes/de-DE/default.txt b/src/frontends/android/app/src/main/play/release-notes/de-DE/default.txt index 5521e02a9..c6923513f 100644 --- a/src/frontends/android/app/src/main/play/release-notes/de-DE/default.txt +++ b/src/frontends/android/app/src/main/play/release-notes/de-DE/default.txt @@ -1,13 +1,6 @@ -# 2.5.2 # +# 2.5.3 # -- Ziel-SDK auf Android 14 erhöht -- Wegen eines Bugs in Android 14 ist eine zusätzliche Permission ist nötig, um von der Status-Kachel eine Verbindung im Hintergrund zu starten -- Fixt einen Crash beim Öffnen der Liste installierter Apps in neuen Profilen - -# 2.5.1 # - -- Fix für existierende Verknüpfungen und Automatisierung via Intents - -# 2.5.0 # - -- Unterstützung für verwaltete Konfigurationen via Enterprise Mobility Management (EMM) +- Unterstützt die Verteilung von Passwörtern in verwalteten Profilen +- Unterstützt den Import von Profil-Dateien mit Passwörtern +- Fixt einen Crash beim Ändern des Passworts von verwalteten Profilen +- Fixt einen Crash beim Importieren eines bereit existierenden Profils diff --git a/src/frontends/android/app/src/main/play/release-notes/en-US/default.txt b/src/frontends/android/app/src/main/play/release-notes/en-US/default.txt index 0dc823127..84153240a 100644 --- a/src/frontends/android/app/src/main/play/release-notes/en-US/default.txt +++ b/src/frontends/android/app/src/main/play/release-notes/en-US/default.txt @@ -1,13 +1,6 @@ -# 2.5.2 # +# 2.5.3 # -- Increased target SDK to Android 14 -- Due to a bug in Android 14, a new permission is necessary to start a profile in the background from the status tile -- Fix crash when listing installed apps for new profiles - -# 2.5.1 # - -- Fix for existing shortcuts and automation via Intents - -# 2.5.0 # - -- Support for managed configurations via enterprise mobility management (EMM) +- Add support for distributing passwords in managed profiles +- Add support for importing profile files with passwords +- Fix crash when editing password of managed profiles +- Fix crash when re-importing an already existing profile diff --git a/src/frontends/android/app/src/main/res/layout/imc_state_fragment.xml b/src/frontends/android/app/src/main/res/layout/imc_state_fragment.xml index c1e278968..ba1762882 100644 --- a/src/frontends/android/app/src/main/res/layout/imc_state_fragment.xml +++ b/src/frontends/android/app/src/main/res/layout/imc_state_fragment.xml @@ -30,15 +30,15 @@ @@ -58,8 +58,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" - android:layout_marginLeft="20dp" - android:layout_marginRight="20dp" + android:layout_marginStart="20dp" + android:layout_marginEnd="20dp" android:text="@string/show_remediation_instructions" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="?android:attr/textColorSecondary" /> 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 5197c63f7..eb67583bb 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 @@ -27,7 +27,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/state_background" - android:drawableStart="@android:drawable/ic_dialog_alert" + app:drawableStartCompat="@android:drawable/ic_dialog_alert" android:drawablePadding="8dp" android:padding="8dp" android:text="@string/alert_text_vpn_profile_read_only" @@ -73,7 +73,7 @@ @@ -140,7 +140,7 @@ @@ -153,8 +153,8 @@ android:id="@+id/install_user_certificate" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="4dp" - android:layout_marginRight="4dp" + android:layout_marginStart="4dp" + android:layout_marginEnd="4dp" android:text="@string/profile_user_certificate_install" /> @@ -162,7 +162,7 @@ @@ -210,7 +210,7 @@ @@ -319,14 +319,12 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="4dp" - android:layout_marginLeft="4dp" android:text="@string/profile_cert_req_label" /> @@ -336,14 +334,12 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="4dp" - android:layout_marginLeft="4dp" android:text="@string/profile_use_ocsp_label" /> @@ -353,14 +349,12 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="4dp" - android:layout_marginLeft="4dp" android:text="@string/profile_use_crl_label" /> @@ -370,14 +364,12 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="4dp" - android:layout_marginLeft="4dp" android:text="@string/profile_strict_revocation_label" /> @@ -387,14 +379,12 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="4dp" - android:layout_marginLeft="4dp" android:text="@string/profile_rsa_pss_label" /> @@ -404,14 +394,12 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="4dp" - android:layout_marginLeft="4dp" android:text="@string/profile_ipv6_transport_label" /> @@ -420,7 +408,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="4dp" - android:layout_marginLeft="4dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:text="@string/profile_split_tunneling_label" @@ -429,7 +416,7 @@ + + @@ -66,7 +78,6 @@ android:id="@+id/name" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="4dp" android:layout_marginStart="4dp" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="?android:attr/textColorPrimary" /> @@ -75,7 +86,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="6dp" - android:layout_marginLeft="4dp" android:layout_marginStart="4dp" android:textSize="12sp" android:text="@string/profile_gateway_label" /> @@ -84,7 +94,6 @@ android:id="@+id/gateway" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="4dp" android:layout_marginStart="4dp" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="?android:attr/textColorPrimary" /> @@ -93,7 +102,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="6dp" - android:layout_marginLeft="4dp" android:layout_marginStart="4dp" android:textSize="12sp" android:text="@string/profile_vpn_type_label" /> @@ -103,7 +111,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="4dp" - android:layout_marginLeft="4dp" android:layout_marginStart="4dp" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="?android:attr/textColorPrimary" /> @@ -162,7 +169,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="4dp" - android:layout_marginLeft="4dp" + android:layout_marginStart="4dp" android:textSize="12sp" android:text="@string/profile_user_certificate_label" /> @@ -174,8 +181,8 @@ android:id="@+id/import_user_certificate" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="4dp" - android:layout_marginRight="4dp" + android:layout_marginStart="4dp" + android:layout_marginEnd="4dp" android:text="@string/profile_cert_import" /> @@ -190,7 +197,7 @@ diff --git a/src/frontends/android/app/src/main/res/layout/profile_list_fragment.xml b/src/frontends/android/app/src/main/res/layout/profile_list_fragment.xml index 7308f6d48..6cc9d5b9c 100644 --- a/src/frontends/android/app/src/main/res/layout/profile_list_fragment.xml +++ b/src/frontends/android/app/src/main/res/layout/profile_list_fragment.xml @@ -19,8 +19,8 @@ android:layout_height="match_parent" android:paddingBottom="10dp" android:paddingTop="10dp" - android:paddingLeft="5dp" - android:paddingRight="5dp" > + android:paddingStart="5dp" + android:paddingEnd="5dp" > diff --git a/src/frontends/android/app/src/main/res/layout/remediation_instruction.xml b/src/frontends/android/app/src/main/res/layout/remediation_instruction.xml index 8bae732f6..9a3899144 100644 --- a/src/frontends/android/app/src/main/res/layout/remediation_instruction.xml +++ b/src/frontends/android/app/src/main/res/layout/remediation_instruction.xml @@ -24,7 +24,7 @@ android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="10dp" + android:layout_marginStart="10dp" android:textIsSelectable="true" android:textAppearance="?android:attr/textAppearanceLarge" /> @@ -32,7 +32,7 @@ android:id="@+id/description" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="10dp" + android:layout_marginStart="10dp" android:textIsSelectable="true" android:textColor="?android:textColorSecondary" android:textAppearance="?android:attr/textAppearanceMedium" /> @@ -41,7 +41,7 @@ android:id="@+id/list_header" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="10dp" + android:layout_marginStart="10dp" android:layout_marginTop="20dp" android:textIsSelectable="true" android:textAppearance="?android:attr/textAppearanceMedium" /> diff --git a/src/frontends/android/app/src/main/res/layout/remediation_instruction_item.xml b/src/frontends/android/app/src/main/res/layout/remediation_instruction_item.xml index cb14fe89a..ddd9f67a5 100644 --- a/src/frontends/android/app/src/main/res/layout/remediation_instruction_item.xml +++ b/src/frontends/android/app/src/main/res/layout/remediation_instruction_item.xml @@ -27,8 +27,8 @@ android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="15dp" - android:layout_marginRight="15dp" + android:layout_marginStart="15dp" + android:layout_marginEnd="15dp" android:textAppearance="?android:attr/textAppearanceMedium" android:textIsSelectable="false" /> @@ -37,8 +37,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@android:id/text1" - android:layout_alignLeft="@android:id/text1" - android:layout_alignRight="@android:id/text1" + android:layout_alignStart="@android:id/text1" + android:layout_alignEnd="@android:id/text1" android:textColor="?android:textColorSecondary" android:textAppearance="?android:attr/textAppearanceSmall" android:singleLine="true" diff --git a/src/frontends/android/app/src/main/res/layout/selected_application_item.xml b/src/frontends/android/app/src/main/res/layout/selected_application_item.xml index aacbb3b09..1f666478a 100644 --- a/src/frontends/android/app/src/main/res/layout/selected_application_item.xml +++ b/src/frontends/android/app/src/main/res/layout/selected_application_item.xml @@ -19,8 +19,8 @@ android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingLeft="8dp" - android:paddingRight="8dp" + android:paddingStart="8dp" + android:paddingEnd="8dp" android:minHeight="?android:listPreferredItemHeight" android:background="@drawable/activated_background" android:gravity="center_vertical" > @@ -29,7 +29,6 @@ android:duplicateParentState="true" android:layout_width="@android:dimen/app_icon_size" android:layout_height="@android:dimen/app_icon_size" - android:layout_marginRight="8dip" android:layout_marginEnd="8dip" android:scaleType="centerInside" /> @@ -47,7 +46,6 @@ android:duplicateParentState="true" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="16dp" android:layout_marginStart="16dp" /> diff --git a/src/frontends/android/app/src/main/res/layout/trusted_certificates_item.xml b/src/frontends/android/app/src/main/res/layout/trusted_certificates_item.xml index 6677a618a..7b54b6751 100644 --- a/src/frontends/android/app/src/main/res/layout/trusted_certificates_item.xml +++ b/src/frontends/android/app/src/main/res/layout/trusted_certificates_item.xml @@ -30,7 +30,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/subject_primary" - android:layout_alignLeft="@id/subject_primary" + android:layout_alignStart="@id/subject_primary" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="?android:attr/textColorSecondary" /> diff --git a/src/frontends/android/app/src/main/res/layout/two_line_button.xml b/src/frontends/android/app/src/main/res/layout/two_line_button.xml index c8edc04c2..f7ceaf1c8 100644 --- a/src/frontends/android/app/src/main/res/layout/two_line_button.xml +++ b/src/frontends/android/app/src/main/res/layout/two_line_button.xml @@ -34,7 +34,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@android:id/text1" - android:layout_alignLeft="@android:id/text1" + android:layout_alignStart="@android:id/text1" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="?android:attr/textColorSecondary" /> diff --git a/src/frontends/android/app/src/main/res/layout/vpn_state_fragment.xml b/src/frontends/android/app/src/main/res/layout/vpn_state_fragment.xml index 4616adf0a..9227007fb 100644 --- a/src/frontends/android/app/src/main/res/layout/vpn_state_fragment.xml +++ b/src/frontends/android/app/src/main/res/layout/vpn_state_fragment.xml @@ -34,8 +34,8 @@ android:id="@+id/vpn_error_text" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="20dp" - android:layout_marginRight="20dp" + android:layout_marginStart="20dp" + android:layout_marginEnd="20dp" android:layout_marginTop="24dp" android:layout_marginBottom="12dp" android:text="Failed to establish VPN: Server is unreachable" @@ -53,7 +53,7 @@ android:id="@+id/show_log" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" + android:layout_marginStart="8dp" android:text="@string/show_log" android:textColor="@color/primary" android:textSize="14sp" @@ -84,8 +84,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" - android:layout_marginLeft="20dp" - android:layout_marginRight="20dp" + android:layout_marginStart="20dp" + android:layout_marginEnd="20dp" android:layout_marginTop="10dp" android:columnCount="2" android:rowCount="2" > @@ -93,7 +93,7 @@ @@ -146,8 +146,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" - android:layout_marginLeft="20dp" - android:layout_marginRight="20dp" + android:layout_marginStart="20dp" + android:layout_marginEnd="20dp" android:text="@string/disconnect" style="?android:attr/borderlessButtonStyle" > 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 4e16f5d8d..f1d297556 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 @@ -136,6 +136,7 @@ TLS-Handshake fehlgeschlagen Ungültiger Wert in \"%1$s\" Dieses VPN Profil existiert bereits, die bestehenden Einstellungen werden ersetzt. + Diese Datei enthält ein Klartext-Passwort. Denken Sie daran, sie nach dem Importieren zu löschen. Zertifikat aus VPN Profil importieren Zertifikat für \"%1$s\" Profil-ID diff --git a/src/frontends/android/app/src/main/res/values-de/strings_managed_configuration.xml b/src/frontends/android/app/src/main/res/values-de/strings_managed_configuration.xml index b64f5461c..74e59cfe7 100644 --- a/src/frontends/android/app/src/main/res/values-de/strings_managed_configuration.xml +++ b/src/frontends/android/app/src/main/res/values-de/strings_managed_configuration.xml @@ -85,6 +85,8 @@ Specifies information about the client Identity/username for EAP authentication (Optional) If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password + Password for EAP authentication (Optional) + If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally @string/profile_local_id_label @string/profile_local_id_hint_user @string/profile_user_certificate_label 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 68089da93..cdf4eccc1 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 @@ -138,6 +138,7 @@ TLS handshake failed Invalid value in \"%1$s\" This VPN profile already exists, its current settings will be replaced. + This file contains a cleartext password. Remember to delete it after importing. Import certificate from VPN profile Certificate for \"%1$s\" Profile ID diff --git a/src/frontends/android/app/src/main/res/values-pl/strings_managed_configuration.xml b/src/frontends/android/app/src/main/res/values-pl/strings_managed_configuration.xml index b64f5461c..74e59cfe7 100644 --- a/src/frontends/android/app/src/main/res/values-pl/strings_managed_configuration.xml +++ b/src/frontends/android/app/src/main/res/values-pl/strings_managed_configuration.xml @@ -85,6 +85,8 @@ Specifies information about the client Identity/username for EAP authentication (Optional) If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password + Password for EAP authentication (Optional) + If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally @string/profile_local_id_label @string/profile_local_id_hint_user @string/profile_user_certificate_label 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 ab35f29e7..d879c9ebe 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 @@ -132,6 +132,7 @@ TLS handshake failed Invalid value in \"%1$s\" This VPN profile already exists, its current settings will be replaced. + This file contains a cleartext password. Remember to delete it after importing. Import certificate from VPN profile Certificate for \"%1$s\" Profile ID diff --git a/src/frontends/android/app/src/main/res/values-ru/strings_managed_configuration.xml b/src/frontends/android/app/src/main/res/values-ru/strings_managed_configuration.xml index b64f5461c..74e59cfe7 100644 --- a/src/frontends/android/app/src/main/res/values-ru/strings_managed_configuration.xml +++ b/src/frontends/android/app/src/main/res/values-ru/strings_managed_configuration.xml @@ -85,6 +85,8 @@ Specifies information about the client Identity/username for EAP authentication (Optional) If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password + Password for EAP authentication (Optional) + If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally @string/profile_local_id_label @string/profile_local_id_hint_user @string/profile_user_certificate_label diff --git a/src/frontends/android/app/src/main/res/values-uk/strings.xml b/src/frontends/android/app/src/main/res/values-uk/strings.xml index 677d7c95d..8eadc5cb3 100644 --- a/src/frontends/android/app/src/main/res/values-uk/strings.xml +++ b/src/frontends/android/app/src/main/res/values-uk/strings.xml @@ -133,6 +133,7 @@ TLS handshake failed Invalid value in \"%1$s\" This VPN profile already exists, its current settings will be replaced. + This file contains a cleartext password. Remember to delete it after importing. Import certificate from VPN profile Certificate for \"%1$s\" Profile ID diff --git a/src/frontends/android/app/src/main/res/values-uk/strings_managed_configuration.xml b/src/frontends/android/app/src/main/res/values-uk/strings_managed_configuration.xml index b64f5461c..74e59cfe7 100644 --- a/src/frontends/android/app/src/main/res/values-uk/strings_managed_configuration.xml +++ b/src/frontends/android/app/src/main/res/values-uk/strings_managed_configuration.xml @@ -85,6 +85,8 @@ Specifies information about the client Identity/username for EAP authentication (Optional) If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password + Password for EAP authentication (Optional) + If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally @string/profile_local_id_label @string/profile_local_id_hint_user @string/profile_user_certificate_label 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 43d3134d9..4cc7295a2 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 @@ -132,6 +132,7 @@ TLS握手失败 无效的值: \"%1$s\" 此VPN配置已经存在,当前设定将被覆盖。 + This file contains a cleartext password. Remember to delete it after importing. 从VPN配置导入证书 \"%1$s\" 所对应的证书 配置文件ID diff --git a/src/frontends/android/app/src/main/res/values-zh-rCN/strings_managed_configuration.xml b/src/frontends/android/app/src/main/res/values-zh-rCN/strings_managed_configuration.xml index b64f5461c..74e59cfe7 100644 --- a/src/frontends/android/app/src/main/res/values-zh-rCN/strings_managed_configuration.xml +++ b/src/frontends/android/app/src/main/res/values-zh-rCN/strings_managed_configuration.xml @@ -85,6 +85,8 @@ Specifies information about the client Identity/username for EAP authentication (Optional) If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password + Password for EAP authentication (Optional) + If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally @string/profile_local_id_label @string/profile_local_id_hint_user @string/profile_user_certificate_label 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 731682f66..303679112 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 @@ -132,6 +132,7 @@ TLS連線失敗 Invalid value in \"%1$s\" 這個VPN設定檔已經存在,當前設定檔會被覆蓋。 + This file contains a cleartext password. Remember to delete it after importing. 從VPN設定檔匯入憑證 \"%1$s\" 對應的憑證 Profile ID diff --git a/src/frontends/android/app/src/main/res/values-zh-rTW/strings_managed_configuration.xml b/src/frontends/android/app/src/main/res/values-zh-rTW/strings_managed_configuration.xml index b64f5461c..74e59cfe7 100644 --- a/src/frontends/android/app/src/main/res/values-zh-rTW/strings_managed_configuration.xml +++ b/src/frontends/android/app/src/main/res/values-zh-rTW/strings_managed_configuration.xml @@ -85,6 +85,8 @@ Specifies information about the client Identity/username for EAP authentication (Optional) If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password + Password for EAP authentication (Optional) + If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally @string/profile_local_id_label @string/profile_local_id_hint_user @string/profile_user_certificate_label 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 71dc6e851..aaf7dd4c2 100644 --- a/src/frontends/android/app/src/main/res/values/strings.xml +++ b/src/frontends/android/app/src/main/res/values/strings.xml @@ -136,6 +136,7 @@ TLS handshake failed Invalid value in \"%1$s\" This VPN profile already exists, its current settings will be replaced. + This file contains a cleartext password. Remember to delete it after importing. Import certificate from VPN profile Certificate for \"%1$s\" Profile ID diff --git a/src/frontends/android/app/src/main/res/values/strings_managed_configuration.xml b/src/frontends/android/app/src/main/res/values/strings_managed_configuration.xml index b64f5461c..74e59cfe7 100644 --- a/src/frontends/android/app/src/main/res/values/strings_managed_configuration.xml +++ b/src/frontends/android/app/src/main/res/values/strings_managed_configuration.xml @@ -85,6 +85,8 @@ Specifies information about the client Identity/username for EAP authentication (Optional) If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it. If it is set, the user is not able to change it. In both cases the user may optionally enter the password + Password for EAP authentication (Optional) + If this is required (for username/password-based EAP authentication) but not configured here, the user is prompted for it and may store it locally @string/profile_local_id_label @string/profile_local_id_hint_user @string/profile_user_certificate_label diff --git a/src/frontends/android/app/src/main/res/xml/managed_configuration.xml b/src/frontends/android/app/src/main/res/xml/managed_configuration.xml index 105b3f839..e86ad721e 100644 --- a/src/frontends/android/app/src/main/res/xml/managed_configuration.xml +++ b/src/frontends/android/app/src/main/res/xml/managed_configuration.xml @@ -176,6 +176,13 @@ android:restrictionType="string" android:title="@string/managed_config_local_eap_id_title" /> + +