Compare commits
22 Commits
laforge/sw
...
master
Author | SHA1 | Date |
---|---|---|
Tobias Brunner | e6a904de69 | |
Tobias Brunner | ce607d774b | |
Tobias Brunner | 1c4e134f26 | |
Noel Kuntze | 5d6e69a6e4 | |
Tobias Brunner | 4ae9b482f2 | |
Tobias Brunner | 1aa68a78f8 | |
Tobias Brunner | 358d3d0ba1 | |
Tobias Brunner | a14337bcde | |
Tobias Brunner | 3eadd0fc3a | |
Tobias Brunner | 2f1bf11dca | |
Tobias Brunner | b3cdbe6693 | |
Tobias Brunner | 26354d0aba | |
Tobias Brunner | a8cc146240 | |
Tobias Brunner | c976165533 | |
Tobias Brunner | dc351a30e1 | |
Tobias Brunner | 93c494e295 | |
Tobias Brunner | 7cd50aeb64 | |
Tobias Brunner | a885e38265 | |
Tobias Brunner | 6f3725ea8b | |
Tobias Brunner | 5831009941 | |
Tobias Brunner | 44e16a63ef | |
Tobias Brunner | 2f9114bce1 |
|
@ -46,7 +46,7 @@ jobs:
|
|||
# for C builds, so we follow the "any CI" instructions
|
||||
- name: Install sonar-scanner
|
||||
env:
|
||||
SONAR_SCANNER_VERSION: 4.4.0.2170
|
||||
SONAR_SCANNER_VERSION: 4.6.2.2472
|
||||
run: |
|
||||
export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux
|
||||
curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux.zip
|
||||
|
|
|
@ -52,3 +52,4 @@ coverage/
|
|||
/*.files
|
||||
/*.includes
|
||||
test-driver
|
||||
nbproject/
|
||||
|
|
|
@ -6,7 +6,7 @@ TARBALL=$SRCDIR/.tarball-git-version
|
|||
if test -f $TARBALL; then
|
||||
V=$(cat $TARBALL)
|
||||
elif test -d $SRCDIR/.git; then
|
||||
V=$(git -C $SRCDIR describe --tags HEAD 2>/dev/null)
|
||||
V=$(git -C $SRCDIR describe --exclude 'android-*' --tags HEAD 2>/dev/null)
|
||||
fi
|
||||
|
||||
if test -z "$V"; then
|
||||
|
|
|
@ -37,7 +37,7 @@ build_botan()
|
|||
|
||||
build_wolfssl()
|
||||
{
|
||||
WOLFSSL_REV=0caf3ba456f1 # v4.7.1r + SHA-3 fix
|
||||
WOLFSSL_REV=v4.8.0-stable
|
||||
WOLFSSL_DIR=$DEPS_BUILD_DIR/wolfssl
|
||||
|
||||
if test -d "$WOLFSSL_DIR"; then
|
||||
|
@ -468,7 +468,7 @@ sonarcloud)
|
|||
-Dsonar.projectKey=${SONAR_PROJECT} \
|
||||
-Dsonar.organization=${SONAR_ORGANIZATION} \
|
||||
-Dsonar.login=${SONAR_TOKEN} \
|
||||
-Dsonar.projectVersion=$(git describe)+${BUILD_NUMBER} \
|
||||
-Dsonar.projectVersion=$(git describe --exclude 'android-*')+${BUILD_NUMBER} \
|
||||
-Dsonar.sources=. \
|
||||
-Dsonar.cfamily.threads=2 \
|
||||
-Dsonar.cfamily.cache.enabled=true \
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 30
|
||||
|
||||
defaultConfig {
|
||||
applicationId "org.strongswan.android"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 29
|
||||
versionCode 74
|
||||
versionName "2.3.2"
|
||||
targetSdkVersion 30
|
||||
versionCode 75
|
||||
versionName "2.3.3"
|
||||
}
|
||||
|
||||
sourceSets.main {
|
||||
|
@ -46,13 +46,13 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
||||
implementation 'androidx.preference:preference:1.1.1'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'com.google.android.material:material:1.2.1'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'org.mockito:mockito-core:2.28.2'
|
||||
testImplementation 'org.powermock:powermock-core:2.0.2'
|
||||
testImplementation 'org.powermock:powermock-module-junit4:2.0.2'
|
||||
testImplementation 'org.powermock:powermock-api-mockito2:2.0.2'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.mockito:mockito-core:3.11.2'
|
||||
testImplementation 'org.powermock:powermock-core:2.0.9'
|
||||
testImplementation 'org.powermock:powermock-module-junit4:2.0.9'
|
||||
testImplementation 'org.powermock:powermock-api-mockito2:2.0.9'
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
<!-- necessary to allow users to select ex-/included apps and EAP-TNC -->
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
|
||||
<application
|
||||
android:name=".logic.StrongSwanApplication"
|
||||
|
|
|
@ -192,7 +192,7 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
|
|||
mAppDir = getFilesDir().getAbsolutePath();
|
||||
|
||||
/* handler used to do changes in the main UI thread */
|
||||
mHandler = new Handler();
|
||||
mHandler = new Handler(getMainLooper());
|
||||
|
||||
mDataSource = new VpnProfileDataSource(this);
|
||||
mDataSource.open();
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
package org.strongswan.android.logic;
|
||||
|
||||
import java.security.Security;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.strongswan.android.security.LocalCertificateKeyStoreProvider;
|
||||
import org.strongswan.android.ui.MainActivity;
|
||||
|
@ -23,10 +26,16 @@ import org.strongswan.android.ui.MainActivity;
|
|||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.core.os.HandlerCompat;
|
||||
|
||||
public class StrongSwanApplication extends Application
|
||||
{
|
||||
private static Context mContext;
|
||||
private final ExecutorService mExecutorService = Executors.newFixedThreadPool(4);
|
||||
private final Handler mMainHandler = HandlerCompat.createAsync(Looper.getMainLooper());
|
||||
|
||||
static {
|
||||
Security.addProvider(new LocalCertificateKeyStoreProvider());
|
||||
|
@ -48,6 +57,24 @@ public class StrongSwanApplication extends Application
|
|||
return StrongSwanApplication.mContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a thread pool to run tasks in separate threads
|
||||
* @return thread pool
|
||||
*/
|
||||
public Executor getExecutor()
|
||||
{
|
||||
return mExecutorService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a handler to execute stuff by the main thread.
|
||||
* @return handler
|
||||
*/
|
||||
public Handler getHandler()
|
||||
{
|
||||
return mMainHandler;
|
||||
}
|
||||
|
||||
/*
|
||||
* The libraries are extracted to /data/data/org.strongswan.android/...
|
||||
* during installation. On newer releases most are loaded in JNI_OnLoad.
|
||||
|
|
|
@ -22,6 +22,7 @@ import android.os.Binder;
|
|||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.SystemClock;
|
||||
|
||||
|
@ -107,7 +108,7 @@ public class VpnStateService extends Service
|
|||
{
|
||||
/* this handler allows us to notify listeners from the UI thread and
|
||||
* not from the threads that actually report any state changes */
|
||||
mHandler = new RetryHandler(this);
|
||||
mHandler = new RetryHandler(getMainLooper(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -536,8 +537,9 @@ public class VpnStateService extends Service
|
|||
private static class RetryHandler extends Handler {
|
||||
WeakReference<VpnStateService> mService;
|
||||
|
||||
public RetryHandler(VpnStateService service)
|
||||
public RetryHandler(Looper looper, VpnStateService service)
|
||||
{
|
||||
super(looper);
|
||||
mService = new WeakReference<>(service);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
package org.strongswan.android.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.FileObserver;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -36,6 +38,7 @@ import java.io.StringReader;
|
|||
import java.util.ArrayList;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
public class LogFragment extends Fragment
|
||||
|
@ -55,9 +58,17 @@ public class LogFragment extends Fragment
|
|||
|
||||
mLogFilePath = getActivity().getFilesDir() + File.separator + CharonVpnService.LOG_FILE;
|
||||
|
||||
mLogHandler = new Handler();
|
||||
mLogHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
mDirectoryObserver = new LogDirectoryObserver(getActivity().getFilesDir().getAbsolutePath());
|
||||
File logdir = getActivity().getFilesDir();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||
{
|
||||
mDirectoryObserver = new LogDirectoryObserver(logdir);
|
||||
}
|
||||
else
|
||||
{
|
||||
mDirectoryObserver = new LogDirectoryObserver(logdir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -223,14 +234,20 @@ public class LogFragment extends Fragment
|
|||
*/
|
||||
private class LogDirectoryObserver extends FileObserver
|
||||
{
|
||||
private final File mFile;
|
||||
private long mSize;
|
||||
private static final int mMask = FileObserver.CREATE | FileObserver.MODIFY | FileObserver.DELETE;
|
||||
private final File mFile = new File(mLogFilePath);
|
||||
private long mSize = mFile.length();
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public LogDirectoryObserver(String path)
|
||||
{
|
||||
super(path, FileObserver.CREATE | FileObserver.MODIFY | FileObserver.DELETE);
|
||||
mFile = new File(mLogFilePath);
|
||||
mSize = mFile.length();
|
||||
super(path, mMask);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.Q)
|
||||
public LogDirectoryObserver(File path)
|
||||
{
|
||||
super(path, mMask);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.strongswan.android.ui;
|
|||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.format.Formatter;
|
||||
|
@ -30,6 +29,7 @@ import android.widget.Toast;
|
|||
|
||||
import org.strongswan.android.R;
|
||||
import org.strongswan.android.data.VpnProfile;
|
||||
import org.strongswan.android.logic.StrongSwanApplication;
|
||||
import org.strongswan.android.logic.TrustedCertificateManager;
|
||||
import org.strongswan.android.ui.VpnProfileListFragment.OnVpnProfileSelectedListener;
|
||||
|
||||
|
@ -68,8 +68,10 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec
|
|||
bar.setDisplayShowTitleEnabled(false);
|
||||
bar.setIcon(R.mipmap.ic_app);
|
||||
|
||||
/* load CA certificates in a background task */
|
||||
new LoadCertificatesTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
/* load CA certificates in a background thread */
|
||||
((StrongSwanApplication)getApplication()).getExecutor().execute(() -> {
|
||||
TrustedCertificateManager.getInstance().load();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -157,18 +159,6 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec
|
|||
dialog.show(this.getSupportFragmentManager(), DIALOG_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that loads the cached CA certificates.
|
||||
*/
|
||||
private class LoadCertificatesTask extends AsyncTask<Void, Void, TrustedCertificateManager>
|
||||
{
|
||||
@Override
|
||||
protected TrustedCertificateManager doInBackground(Void... params)
|
||||
{
|
||||
return TrustedCertificateManager.getInstance().load();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss dialog if shown
|
||||
*/
|
||||
|
|
|
@ -26,6 +26,8 @@ import android.widget.TextView;
|
|||
import org.strongswan.android.R;
|
||||
import org.strongswan.android.logic.imc.RemediationInstruction;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.ListFragment;
|
||||
|
||||
public class RemediationInstructionFragment extends ListFragment
|
||||
|
@ -49,9 +51,9 @@ public class RemediationInstructionFragment extends ListFragment
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState)
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
|
||||
{
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
if (savedInstanceState != null)
|
||||
{
|
||||
|
|
|
@ -26,6 +26,8 @@ import org.strongswan.android.ui.adapter.RemediationInstructionAdapter;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.ListFragment;
|
||||
|
||||
public class RemediationInstructionsFragment extends ListFragment
|
||||
|
@ -46,9 +48,9 @@ public class RemediationInstructionsFragment extends ListFragment
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState)
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
|
||||
{
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
if (savedInstanceState != null)
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@ import java.util.List;
|
|||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.fragment.app.ListFragment;
|
||||
|
@ -53,9 +54,9 @@ public class SelectedApplicationsListFragment extends ListFragment implements Lo
|
|||
private SortedSet<String> mSelection;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable Bundle savedInstanceState)
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
|
||||
{
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package org.strongswan.android.ui;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.DialogInterface;
|
||||
|
@ -37,6 +36,8 @@ import java.security.cert.CertificateException;
|
|||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDialogFragment;
|
||||
|
@ -44,10 +45,21 @@ import androidx.fragment.app.FragmentTransaction;
|
|||
|
||||
public class TrustedCertificateImportActivity extends AppCompatActivity
|
||||
{
|
||||
private static final int OPEN_DOCUMENT = 0;
|
||||
private static final String DIALOG_TAG = "Dialog";
|
||||
private Uri mCertificateUri;
|
||||
|
||||
private final ActivityResultLauncher<Intent> mOpenDocument = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == RESULT_OK && result.getData() != null)
|
||||
{
|
||||
mCertificateUri = result.getData().getData();
|
||||
return;
|
||||
}
|
||||
finish();
|
||||
}
|
||||
);
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
|
@ -71,7 +83,7 @@ public class TrustedCertificateImportActivity extends AppCompatActivity
|
|||
openIntent.setType("*/*");
|
||||
try
|
||||
{
|
||||
startActivityForResult(openIntent, OPEN_DOCUMENT);
|
||||
mOpenDocument.launch(openIntent);
|
||||
}
|
||||
catch (ActivityNotFoundException e)
|
||||
{ /* some devices are unable to browse for files */
|
||||
|
@ -81,23 +93,6 @@ public class TrustedCertificateImportActivity extends AppCompatActivity
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
switch (requestCode)
|
||||
{
|
||||
case OPEN_DOCUMENT:
|
||||
if (resultCode == Activity.RESULT_OK && data != null)
|
||||
{
|
||||
mCertificateUri = data.getData();
|
||||
return;
|
||||
}
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume()
|
||||
{
|
||||
|
@ -214,7 +209,7 @@ public class TrustedCertificateImportActivity extends AppCompatActivity
|
|||
if (activity.storeCertificate(certificate))
|
||||
{
|
||||
Toast.makeText(getActivity(), R.string.cert_imported_successfully, Toast.LENGTH_LONG).show();
|
||||
getActivity().setResult(Activity.RESULT_OK);
|
||||
getActivity().setResult(RESULT_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -41,6 +41,8 @@ import java.util.Map.Entry;
|
|||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.ListFragment;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.app.LoaderManager.LoaderCallbacks;
|
||||
|
@ -63,9 +65,9 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState)
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
|
||||
{
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
setEmptyText(getString(R.string.no_certificates));
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
|
||||
package org.strongswan.android.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
@ -24,6 +22,7 @@ import android.view.Menu;
|
|||
import android.view.MenuItem;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
import org.strongswan.android.R;
|
||||
import org.strongswan.android.data.VpnProfileDataSource;
|
||||
|
@ -34,22 +33,34 @@ import org.strongswan.android.ui.CertificateDeleteConfirmationDialog.OnCertifica
|
|||
|
||||
import java.security.KeyStore;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
public class TrustedCertificatesActivity extends AppCompatActivity implements TrustedCertificateListFragment.OnTrustedCertificateSelectedListener, OnCertificateDeleteListener
|
||||
{
|
||||
public static final String SELECT_CERTIFICATE = "org.strongswan.android.action.SELECT_CERTIFICATE";
|
||||
private static final String DIALOG_TAG = "Dialog";
|
||||
private static final int IMPORT_CERTIFICATE = 0;
|
||||
private TrustedCertificatesPagerAdapter mAdapter;
|
||||
private ViewPager mPager;
|
||||
private ViewPager2 mPager;
|
||||
private boolean mSelect;
|
||||
|
||||
private final ActivityResultLauncher<Intent> mImportCertificate = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == RESULT_OK)
|
||||
{
|
||||
reloadCertificates();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
|
@ -59,13 +70,15 @@ public class TrustedCertificatesActivity extends AppCompatActivity implements Tr
|
|||
ActionBar actionBar = getSupportActionBar();
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
mAdapter = new TrustedCertificatesPagerAdapter(getSupportFragmentManager(), this);
|
||||
mAdapter = new TrustedCertificatesPagerAdapter(this);
|
||||
|
||||
mPager = (ViewPager)findViewById(R.id.viewpager);
|
||||
mPager = (ViewPager2)findViewById(R.id.viewpager);
|
||||
mPager.setAdapter(mAdapter);
|
||||
|
||||
TabLayout tabs = (TabLayout)findViewById(R.id.tabs);
|
||||
tabs.setupWithViewPager(mPager);
|
||||
new TabLayoutMediator(tabs, mPager, (tab, position) -> {
|
||||
tab.setText(mAdapter.getTitle(position));
|
||||
}).attach();
|
||||
|
||||
mSelect = SELECT_CERTIFICATE.equals(getIntent().getAction());
|
||||
}
|
||||
|
@ -100,27 +113,12 @@ public class TrustedCertificatesActivity extends AppCompatActivity implements Tr
|
|||
return true;
|
||||
case R.id.menu_import_certificate:
|
||||
Intent intent = new Intent(this, TrustedCertificateImportActivity.class);
|
||||
startActivityForResult(intent, IMPORT_CERTIFICATE);
|
||||
mImportCertificate.launch(intent);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
switch (requestCode)
|
||||
{
|
||||
case IMPORT_CERTIFICATE:
|
||||
if (resultCode == Activity.RESULT_OK)
|
||||
{
|
||||
reloadCertificates();
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrustedCertificateSelected(TrustedCertificateEntry selected)
|
||||
{
|
||||
|
@ -129,7 +127,7 @@ public class TrustedCertificatesActivity extends AppCompatActivity implements Tr
|
|||
/* the user selected a certificate, return to calling activity */
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(VpnProfileDataSource.KEY_CERTIFICATE, selected.getAlias());
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
setResult(RESULT_OK, intent);
|
||||
finish();
|
||||
}
|
||||
else if (mAdapter.getSource(mPager.getCurrentItem()) == TrustedCertificateSource.LOCAL)
|
||||
|
@ -163,28 +161,21 @@ public class TrustedCertificatesActivity extends AppCompatActivity implements Tr
|
|||
TrustedCertificateManager.getInstance().reset();
|
||||
}
|
||||
|
||||
public static class TrustedCertificatesPagerAdapter extends FragmentPagerAdapter
|
||||
public static class TrustedCertificatesPagerAdapter extends FragmentStateAdapter
|
||||
{
|
||||
private TrustedCertificatesTab mTabs[];
|
||||
|
||||
public TrustedCertificatesPagerAdapter(FragmentManager fm, Context context)
|
||||
public TrustedCertificatesPagerAdapter(@NonNull FragmentActivity fragmentActivity)
|
||||
{
|
||||
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||
super(fragmentActivity);
|
||||
mTabs = new TrustedCertificatesTab[]{
|
||||
new TrustedCertificatesTab(context.getString(R.string.system_tab), TrustedCertificateSource.SYSTEM),
|
||||
new TrustedCertificatesTab(context.getString(R.string.user_tab), TrustedCertificateSource.USER),
|
||||
new TrustedCertificatesTab(context.getString(R.string.local_tab), TrustedCertificateSource.LOCAL),
|
||||
new TrustedCertificatesTab(fragmentActivity.getString(R.string.system_tab), TrustedCertificateSource.SYSTEM),
|
||||
new TrustedCertificatesTab(fragmentActivity.getString(R.string.user_tab), TrustedCertificateSource.USER),
|
||||
new TrustedCertificatesTab(fragmentActivity.getString(R.string.local_tab), TrustedCertificateSource.LOCAL),
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount()
|
||||
{
|
||||
return mTabs.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position)
|
||||
public CharSequence getTitle(int position)
|
||||
{
|
||||
return mTabs[position].getTitle();
|
||||
}
|
||||
|
@ -195,7 +186,14 @@ public class TrustedCertificatesActivity extends AppCompatActivity implements Tr
|
|||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position)
|
||||
public int getItemCount()
|
||||
{
|
||||
return mTabs.length;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position)
|
||||
{
|
||||
TrustedCertificateListFragment fragment = new TrustedCertificateListFragment();
|
||||
Bundle args = new Bundle();
|
||||
|
|
|
@ -44,6 +44,8 @@ import org.strongswan.android.logic.VpnStateService;
|
|||
import org.strongswan.android.logic.VpnStateService.State;
|
||||
import org.strongswan.android.utils.Constants;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
@ -59,8 +61,6 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
|||
public static final String DISCONNECT = "org.strongswan.android.action.DISCONNECT";
|
||||
public static final String EXTRA_VPN_PROFILE_ID = "org.strongswan.android.VPN_PROFILE_ID";
|
||||
|
||||
private static final int PREPARE_VPN_SERVICE = 0;
|
||||
private static final int ADD_TO_POWER_WHITELIST = 1;
|
||||
private static final String WAITING_FOR_RESULT = "WAITING_FOR_RESULT";
|
||||
private static final String PROFILE_NAME = "PROFILE_NAME";
|
||||
private static final String PROFILE_REQUIRES_PASSWORD = "REQUIRES_PASSWORD";
|
||||
|
@ -87,6 +87,33 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
|||
}
|
||||
};
|
||||
|
||||
private final ActivityResultLauncher<Intent> mPrepareVpnService = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
mWaitingForResult = false;
|
||||
if (result.getResultCode() == RESULT_OK && mProfileInfo != null)
|
||||
{
|
||||
onVpnServicePrepared();
|
||||
}
|
||||
else
|
||||
{ /* this happens if the always-on VPN feature is activated by a different app or the user declined */
|
||||
VpnNotSupportedError.showWithMessage(this, R.string.vpn_not_supported_no_permission);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
private final ActivityResultLauncher<Intent> mAddToPowerWhitelist = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
mWaitingForResult = false;
|
||||
if (mProfileInfo != null && mService != null)
|
||||
{
|
||||
mService.connect(mProfileInfo, true);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
|
@ -173,7 +200,7 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
|||
try
|
||||
{
|
||||
mWaitingForResult = true;
|
||||
startActivityForResult(intent, PREPARE_VPN_SERVICE);
|
||||
mPrepareVpnService.launch(intent);
|
||||
}
|
||||
catch (ActivityNotFoundException ex)
|
||||
{
|
||||
|
@ -187,7 +214,23 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
|||
}
|
||||
else
|
||||
{ /* user already granted permission to use VpnService */
|
||||
onActivityResult(PREPARE_VPN_SERVICE, RESULT_OK, null);
|
||||
onVpnServicePrepared();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called once the VpnService has been prepared and permission has been granted
|
||||
* by the user.
|
||||
*/
|
||||
protected void onVpnServicePrepared()
|
||||
{
|
||||
if (checkPowerWhitelist())
|
||||
{
|
||||
if (mService != null)
|
||||
{
|
||||
mService.connect(mProfileInfo, true);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,48 +262,6 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
switch (requestCode)
|
||||
{
|
||||
case PREPARE_VPN_SERVICE:
|
||||
mWaitingForResult = false;
|
||||
if (resultCode == RESULT_OK && mProfileInfo != null)
|
||||
{
|
||||
if (checkPowerWhitelist())
|
||||
{
|
||||
if (mService != null)
|
||||
{
|
||||
mService.connect(mProfileInfo, true);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* this happens if the always-on VPN feature is activated by a different app or the user declined */
|
||||
if (getSupportFragmentManager().isStateSaved())
|
||||
{ /* onActivityResult() might be called when we aren't active anymore e.g. if the
|
||||
* user pressed the home button, if the activity is started again we land here
|
||||
* before onNewIntent() is called */
|
||||
return;
|
||||
}
|
||||
VpnNotSupportedError.showWithMessage(this, R.string.vpn_not_supported_no_permission);
|
||||
}
|
||||
break;
|
||||
case ADD_TO_POWER_WHITELIST:
|
||||
mWaitingForResult = false;
|
||||
if (mProfileInfo != null && mService != null)
|
||||
{
|
||||
mService.connect(mProfileInfo, true);
|
||||
}
|
||||
finish();
|
||||
break;
|
||||
default:
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are currently connected to a VPN connection
|
||||
*
|
||||
|
@ -597,7 +598,7 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
|||
activity.mWaitingForResult = true;
|
||||
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
|
||||
Uri.parse("package:" + activity.getPackageName()));
|
||||
activity.startActivityForResult(intent, ADD_TO_POWER_WHITELIST);
|
||||
activity.mAddToPowerWhitelist.launch(intent);
|
||||
}).create();
|
||||
}
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@ import android.app.Dialog;
|
|||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.security.KeyChain;
|
||||
import android.security.KeyChainAliasCallback;
|
||||
import android.security.KeyChainException;
|
||||
|
@ -43,6 +43,7 @@ import android.view.ViewGroup;
|
|||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
|
@ -50,7 +51,6 @@ import android.widget.EditText;
|
|||
import android.widget.MultiAutoCompleteTextView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.strongswan.android.R;
|
||||
|
@ -59,6 +59,7 @@ import org.strongswan.android.data.VpnProfile.SelectedAppsHandling;
|
|||
import org.strongswan.android.data.VpnProfileDataSource;
|
||||
import org.strongswan.android.data.VpnType;
|
||||
import org.strongswan.android.data.VpnType.VpnTypeFeature;
|
||||
import org.strongswan.android.logic.StrongSwanApplication;
|
||||
import org.strongswan.android.logic.TrustedCertificateManager;
|
||||
import org.strongswan.android.security.TrustedCertificateEntry;
|
||||
import org.strongswan.android.ui.adapter.CertificateIdentitiesAdapter;
|
||||
|
@ -73,18 +74,19 @@ import java.util.ArrayList;
|
|||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDialogFragment;
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
public class VpnProfileDetailActivity extends AppCompatActivity
|
||||
{
|
||||
private static final int SELECT_TRUSTED_CERTIFICATE = 0;
|
||||
private static final int SELECT_APPLICATIONS = 1;
|
||||
|
||||
private VpnProfileDataSource mDataSource;
|
||||
private Long mId;
|
||||
private TrustedCertificateEntry mCertEntry;
|
||||
|
@ -119,12 +121,12 @@ public class VpnProfileDetailActivity extends AppCompatActivity
|
|||
private TextInputLayoutHelper mMTUWrap;
|
||||
private EditText mPort;
|
||||
private TextInputLayoutHelper mPortWrap;
|
||||
private Switch mCertReq;
|
||||
private Switch mUseCrl;
|
||||
private Switch mUseOcsp;
|
||||
private Switch mStrictRevocation;
|
||||
private Switch mRsaPss;
|
||||
private Switch mIPv6Transport;
|
||||
private SwitchCompat mCertReq;
|
||||
private SwitchCompat mUseCrl;
|
||||
private SwitchCompat mUseOcsp;
|
||||
private SwitchCompat mStrictRevocation;
|
||||
private SwitchCompat mRsaPss;
|
||||
private SwitchCompat mIPv6Transport;
|
||||
private EditText mNATKeepalive;
|
||||
private TextInputLayoutHelper mNATKeepaliveWrap;
|
||||
private EditText mIncludedSubnets;
|
||||
|
@ -144,6 +146,41 @@ public class VpnProfileDetailActivity extends AppCompatActivity
|
|||
private EditText mDnsServers;
|
||||
private TextInputLayoutHelper mDnsServersWrap;
|
||||
|
||||
private final ActivityResultLauncher<Intent> mInstallPKCS12 = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == RESULT_OK)
|
||||
{
|
||||
mSelectUserCert.performClick();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
private final ActivityResultLauncher<Intent> mSelectTrustedCertificate = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == RESULT_OK)
|
||||
{
|
||||
String alias = result.getData().getStringExtra(VpnProfileDataSource.KEY_CERTIFICATE);
|
||||
X509Certificate certificate = TrustedCertificateManager.getInstance().getCACertificateFromAlias(alias);
|
||||
mCertEntry = certificate == null ? null : new TrustedCertificateEntry(alias, certificate);
|
||||
updateCertificateSelector();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
private final ActivityResultLauncher<Intent> mSelectApplications = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == RESULT_OK)
|
||||
{
|
||||
ArrayList<String> selection = result.getData().getStringArrayListExtra(VpnProfileDataSource.KEY_SELECTED_APPS_LIST);
|
||||
mSelectedApps = new TreeSet<>(selection);
|
||||
updateAppsSelector();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
|
@ -190,7 +227,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity
|
|||
mPortWrap = (TextInputLayoutHelper) findViewById(R.id.port_wrap);
|
||||
mNATKeepalive = (EditText)findViewById(R.id.nat_keepalive);
|
||||
mNATKeepaliveWrap = (TextInputLayoutHelper) findViewById(R.id.nat_keepalive_wrap);
|
||||
mCertReq = (Switch)findViewById(R.id.cert_req);
|
||||
mCertReq = findViewById(R.id.cert_req);
|
||||
mUseCrl = findViewById(R.id.use_crl);
|
||||
mUseOcsp = findViewById(R.id.use_ocsp);
|
||||
mStrictRevocation= findViewById(R.id.strict_revocation);
|
||||
|
@ -283,6 +320,10 @@ public class VpnProfileDetailActivity extends AppCompatActivity
|
|||
});
|
||||
|
||||
mSelectUserCert.setOnClickListener(new SelectUserCertOnClickListener());
|
||||
((Button)findViewById(R.id.install_user_certificate)).setOnClickListener(v -> {
|
||||
Intent intent = KeyChain.createInstallIntent();
|
||||
mInstallPKCS12.launch(intent);
|
||||
});
|
||||
mSelectUserIdAdapter = new CertificateIdentitiesAdapter(this);
|
||||
mLocalId.setAdapter(mSelectUserIdAdapter);
|
||||
|
||||
|
@ -300,7 +341,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity
|
|||
{
|
||||
Intent intent = new Intent(VpnProfileDetailActivity.this, TrustedCertificatesActivity.class);
|
||||
intent.setAction(TrustedCertificatesActivity.SELECT_CERTIFICATE);
|
||||
startActivityForResult(intent, SELECT_TRUSTED_CERTIFICATE);
|
||||
mSelectTrustedCertificate.launch(intent);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -334,7 +375,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity
|
|||
{
|
||||
Intent intent = new Intent(VpnProfileDetailActivity.this, SelectedApplicationsActivity.class);
|
||||
intent.putExtra(VpnProfileDataSource.KEY_SELECTED_APPS_LIST, new ArrayList<>(mSelectedApps));
|
||||
startActivityForResult(intent, SELECT_APPLICATIONS);
|
||||
mSelectApplications.launch(intent);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -404,33 +445,6 @@ public class VpnProfileDetailActivity extends AppCompatActivity
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
switch (requestCode)
|
||||
{
|
||||
case SELECT_TRUSTED_CERTIFICATE:
|
||||
if (resultCode == RESULT_OK)
|
||||
{
|
||||
String alias = data.getStringExtra(VpnProfileDataSource.KEY_CERTIFICATE);
|
||||
X509Certificate certificate = TrustedCertificateManager.getInstance().getCACertificateFromAlias(alias);
|
||||
mCertEntry = certificate == null ? null : new TrustedCertificateEntry(alias, certificate);
|
||||
updateCertificateSelector();
|
||||
}
|
||||
break;
|
||||
case SELECT_APPLICATIONS:
|
||||
if (resultCode == RESULT_OK)
|
||||
{
|
||||
ArrayList<String> selection = data.getStringArrayListExtra(VpnProfileDataSource.KEY_SELECTED_APPS_LIST);
|
||||
mSelectedApps = new TreeSet<>(selection);
|
||||
updateAppsSelector();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the UI to enter credentials depending on the type of VPN currently selected
|
||||
*/
|
||||
|
@ -791,9 +805,22 @@ public class VpnProfileDetailActivity extends AppCompatActivity
|
|||
useralias = savedInstanceState == null ? useralias : savedInstanceState.getString(VpnProfileDataSource.KEY_USER_CERTIFICATE);
|
||||
if (useralias != null)
|
||||
{
|
||||
UserCertificateLoader loader = new UserCertificateLoader(this, useralias);
|
||||
mUserCertLoading = useralias;
|
||||
loader.execute();
|
||||
UserCertificateLoader loader = new UserCertificateLoader(((StrongSwanApplication)getApplication()).getExecutor(),
|
||||
((StrongSwanApplication)getApplication()).getHandler());
|
||||
loader.loadCertifiate(this, useralias, result -> {
|
||||
if (result != null)
|
||||
{
|
||||
mUserCertEntry = new TrustedCertificateEntry(mUserCertLoading, result);
|
||||
}
|
||||
else
|
||||
{ /* previously selected certificate is not here anymore */
|
||||
((TextView)mSelectUserCert.findViewById(android.R.id.text1)).setError("");
|
||||
mUserCertEntry = null;
|
||||
}
|
||||
mUserCertLoading = null;
|
||||
updateCredentialView();
|
||||
});
|
||||
}
|
||||
|
||||
/* check if the user selected a CA certificate previously */
|
||||
|
@ -961,55 +988,53 @@ public class VpnProfileDetailActivity extends AppCompatActivity
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface for the user certificate loader.
|
||||
*/
|
||||
private interface UserCertificateLoaderCallback {
|
||||
void onComplete(X509Certificate result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the selected user certificate asynchronously. This cannot be done
|
||||
* from the main thread as getCertificateChain() calls back to our main
|
||||
* thread to bind to the KeyChain service resulting in a deadlock.
|
||||
*/
|
||||
private class UserCertificateLoader extends AsyncTask<Void, Void, X509Certificate>
|
||||
private class UserCertificateLoader
|
||||
{
|
||||
private final Context mContext;
|
||||
private final String mAlias;
|
||||
private final Executor mExecutor;
|
||||
private final Handler mHandler;
|
||||
|
||||
public UserCertificateLoader(Context context, String alias)
|
||||
public UserCertificateLoader(Executor executor, Handler handler)
|
||||
{
|
||||
mContext = context;
|
||||
mAlias = alias;
|
||||
mExecutor = executor;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X509Certificate doInBackground(Void... params)
|
||||
public void loadCertifiate(Context context, String alias, UserCertificateLoaderCallback callback)
|
||||
{
|
||||
X509Certificate[] chain = null;
|
||||
try
|
||||
{
|
||||
chain = KeyChain.getCertificateChain(mContext, mAlias);
|
||||
}
|
||||
catch (KeyChainException | InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (chain != null && chain.length > 0)
|
||||
{
|
||||
return chain[0];
|
||||
}
|
||||
return null;
|
||||
mExecutor.execute(() -> {
|
||||
X509Certificate[] chain = null;
|
||||
try
|
||||
{
|
||||
chain = KeyChain.getCertificateChain(context, alias);
|
||||
}
|
||||
catch (KeyChainException | InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (chain != null && chain.length > 0)
|
||||
{
|
||||
complete(chain[0], callback);
|
||||
return;
|
||||
}
|
||||
complete(null, callback);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(X509Certificate result)
|
||||
protected void complete(X509Certificate result, UserCertificateLoaderCallback callback)
|
||||
{
|
||||
if (result != null)
|
||||
{
|
||||
mUserCertEntry = new TrustedCertificateEntry(mAlias, result);
|
||||
}
|
||||
else
|
||||
{ /* previously selected certificate is not here anymore */
|
||||
((TextView)mSelectUserCert.findViewById(android.R.id.text1)).setError("");
|
||||
mUserCertEntry = null;
|
||||
}
|
||||
mUserCertLoading = null;
|
||||
updateCredentialView();
|
||||
mHandler.post(() -> callback.onComplete(result));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
package org.strongswan.android.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
|
@ -74,6 +73,8 @@ import java.util.UUID;
|
|||
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.AsyncTaskLoader;
|
||||
|
@ -84,8 +85,6 @@ public class VpnProfileImportActivity extends AppCompatActivity
|
|||
{
|
||||
private static final String PKCS12_INSTALLED = "PKCS12_INSTALLED";
|
||||
private static final String PROFILE_URI = "PROFILE_URI";
|
||||
private static final int INSTALL_PKCS12 = 0;
|
||||
private static final int OPEN_DOCUMENT = 1;
|
||||
private static final int PROFILE_LOADER = 0;
|
||||
private static final int USER_CERT_LOADER = 1;
|
||||
|
||||
|
@ -112,6 +111,29 @@ public class VpnProfileImportActivity extends AppCompatActivity
|
|||
private ViewGroup mRemoteCertificate;
|
||||
private RelativeLayout mRemoteCert;
|
||||
|
||||
private final ActivityResultLauncher<Intent> mImportPKCS12 = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == RESULT_OK)
|
||||
{ /* no need to import twice */
|
||||
mImportUserCert.setEnabled(false);
|
||||
mSelectUserCert.performClick();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
private final ActivityResultLauncher<Intent> mOpenDocument = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == RESULT_OK && result.getData() != null)
|
||||
{
|
||||
loadProfile(result.getData().getData());
|
||||
return;
|
||||
}
|
||||
finish();
|
||||
}
|
||||
);
|
||||
|
||||
private LoaderManager.LoaderCallbacks<ProfileLoadResult> mProfileLoaderCallbacks = new LoaderManager.LoaderCallbacks<ProfileLoadResult>()
|
||||
{
|
||||
@Override
|
||||
|
@ -200,7 +222,7 @@ public class VpnProfileImportActivity extends AppCompatActivity
|
|||
Intent intent = KeyChain.createInstallIntent();
|
||||
intent.putExtra(KeyChain.EXTRA_NAME, getString(R.string.profile_cert_alias, mProfile.getName()));
|
||||
intent.putExtra(KeyChain.EXTRA_PKCS12, mProfile.PKCS12);
|
||||
startActivityForResult(intent, INSTALL_PKCS12);
|
||||
mImportPKCS12.launch(intent);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -216,7 +238,7 @@ public class VpnProfileImportActivity extends AppCompatActivity
|
|||
openIntent.setType("*/*");
|
||||
try
|
||||
{
|
||||
startActivityForResult(openIntent, OPEN_DOCUMENT);
|
||||
mOpenDocument.launch(openIntent);
|
||||
}
|
||||
catch (ActivityNotFoundException e)
|
||||
{ /* some devices are unable to browse for files */
|
||||
|
@ -283,30 +305,6 @@ public class VpnProfileImportActivity extends AppCompatActivity
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
switch (requestCode)
|
||||
{
|
||||
case INSTALL_PKCS12:
|
||||
if (resultCode == Activity.RESULT_OK)
|
||||
{ /* no need to import twice */
|
||||
mImportUserCert.setEnabled(false);
|
||||
mSelectUserCert.performClick();
|
||||
}
|
||||
break;
|
||||
case OPEN_DOCUMENT:
|
||||
if (resultCode == Activity.RESULT_OK && data != null)
|
||||
{
|
||||
loadProfile(data.getData());
|
||||
return;
|
||||
}
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void loadProfile(Uri uri)
|
||||
{
|
||||
mProgressBar.show();
|
||||
|
|
|
@ -55,8 +55,6 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|||
public class VpnProfileListFragment extends Fragment
|
||||
{
|
||||
private static final String SELECTED_KEY = "SELECTED";
|
||||
private static final int ADD_REQUEST = 1;
|
||||
private static final int EDIT_REQUEST = 2;
|
||||
|
||||
private List<VpnProfile> mVpnProfiles;
|
||||
private VpnProfileDataSource mDataSource;
|
||||
|
@ -212,7 +210,7 @@ public class VpnProfileListFragment extends Fragment
|
|||
case R.id.add_profile:
|
||||
Intent connectionIntent = new Intent(getActivity(),
|
||||
VpnProfileDetailActivity.class);
|
||||
startActivityForResult(connectionIntent, ADD_REQUEST);
|
||||
startActivity(connectionIntent);
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
|
@ -270,7 +268,7 @@ public class VpnProfileListFragment extends Fragment
|
|||
VpnProfile profile = (VpnProfile)mListView.getItemAtPosition(position);
|
||||
Intent connectionIntent = new Intent(getActivity(), VpnProfileDetailActivity.class);
|
||||
connectionIntent.putExtra(VpnProfileDataSource.KEY_ID, profile.getId());
|
||||
startActivityForResult(connectionIntent, EDIT_REQUEST);
|
||||
startActivity(connectionIntent);
|
||||
break;
|
||||
}
|
||||
case R.id.copy_profile:
|
||||
|
@ -288,7 +286,7 @@ public class VpnProfileListFragment extends Fragment
|
|||
|
||||
Intent connectionIntent = new Intent(getActivity(), VpnProfileDetailActivity.class);
|
||||
connectionIntent.putExtra(VpnProfileDataSource.KEY_ID, profile.getId());
|
||||
startActivityForResult(connectionIntent, EDIT_REQUEST);
|
||||
startActivity(connectionIntent);
|
||||
break;
|
||||
}
|
||||
case R.id.delete_profile:
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
en-US
|
|
@ -0,0 +1,41 @@
|
|||
Dies ist die offizielle Android-Portierung der populären strongSwan VPN-Lösung.
|
||||
|
||||
# MERKMALE UND EINSCHRÄNKUNGEN #
|
||||
|
||||
<ul>
|
||||
<li>Verwendet die VpnService API von Android 4+. Geräte von einigen Herstellern scheinen diese nicht zu unterstützen - strongSwan wird auf diesen Geräten nicht funktionieren!</li>
|
||||
<li>Verwendet das IKEv2 Schlüsselaustausch-Protokoll (IKEv1 wird nicht unterstützt)</li>
|
||||
<li>Verwendet IPsec für den Datenkanal (L2TP wird nicht unterstützt)</li>
|
||||
<li>Volle Unterstützung für Konnektivitätsänderungen und Mobilität via MOBIKE (oder Re-Authentisierung)</li>
|
||||
<li>Zur Authentisierung der Nutzer wird sowohl einfache auf Benutzername und Passwort basierende EAP-Authentisierung (namentlich EAP-MSCHAPv2, EAP-MD5 und EAP-GTC), sowie zertifikatsbasierte RSA/ECSA-Authentisierung unterstützt, EAP-TLS mit Benutzer-Zertifikaten wird ebenfalls unterstützt</li>
|
||||
<li>Kombinierte Authentisierung mit RSA/ECDSA und EAP wird über zwei Authentisierungsrunden nach RFC 4739 unterstützt</li>
|
||||
<li>Auf dem System vorinstallierte oder durch den Benutzer hinzugefügte CA-Zertifikate werden zur Verifizierung der Server-Zertifikate verwendet. Die CA- oder Server-Zertifikate zur Authentisierung des Server können auch direkt in der App importiert werden.</li>
|
||||
<li>IKEv2-Fragmentierung wird unterstützt, sofern der VPN Server dies ebenfalls tut (strongSwan seit 5.2.1)</li>
|
||||
<li>Split-Tunneling erlaubt das Senden von ausschliesslich ausgewähltem Netzwerkverkehr via VPN und/oder bestimmten Verkehr davon auszuschliessen</li>
|
||||
<li>Per-App VPN erlaubt die VPN-Verbindung nur bestimmten Apps zur Verfügung zu stellen bzw. ausgewählte Apps von der Nutzung des VPN auszuschliessen</li>
|
||||
<li>Die IPsec-Implementierung unterstützt derzeit die AES-CBC, AES-GCM, ChaCha20/Poly1305 und SHA1/SHA2-Algorithmen</li>
|
||||
<li>Passwörter werden zurzeit als Klartext in der Datenbank gespeichert (nur wenn diese mit einem Profil gespeichert werden)</li>
|
||||
<li>VPN Profile können von Dateien importiert werden</li>
|
||||
</ul>
|
||||
|
||||
Details und ein Changelog sind auf unserem Wiki zu finden: https://wiki.strongswan.org/projects/strongswan/wiki/AndroidVPNClient
|
||||
|
||||
# PERMISSIONS #
|
||||
|
||||
<ul>
|
||||
<li>READ_EXTERNAL_STORAGE: Erlaubt den Import von VPN Profilen und CA Zertifikaten von externen Speichern unter bestimmten Android-Versionen</li>
|
||||
<li>QUERY_ALL_PACKAGES: Benötigt unter Android 11+ für die Auswahl von Apps in VPN Profilen und den optionalen EAP-TNC Anwendungsfall</li>
|
||||
</ul>
|
||||
|
||||
# BEISPIEL-SERVERKONFIGURATION #
|
||||
|
||||
Sie finden in unserem Wiki Beispiel-Serverkonfigurationen: https://wiki.strongswan.org/projects/strongswan/wiki/AndroidVPNClient#Server-Configuration
|
||||
|
||||
Beachten Sie bitte, dass der im VPN Profil konfigurierte Hostname (bzw. die IP-Adresse) *zwingend* als subjectAltName-Extension im Server-Zertifikat vorhanden sein muss.
|
||||
|
||||
# FEEDBACK #
|
||||
|
||||
Bitte senden Sie uns Ihre Bug-Reports und Feature-Requests über GitHub: https://github.com/strongswan/strongswan/issues/new/choose
|
||||
Falls Sie dies tun, so fügen Sie bitte Informationen über Ihr Gerät bei (Hersteller, Modell, OS Version usw.).
|
||||
|
||||
Die Log-Datei des Schlüsselaustausch-Dienstes kann direkt aus der Anwendung heraus via E-Mail versendet werden.
|
|
@ -0,0 +1 @@
|
|||
Ein einfach zu bedienender IKEv2/IPsec-basierter VPN-Client.
|
|
@ -0,0 +1,41 @@
|
|||
Official Android port of the popular strongSwan VPN solution.
|
||||
|
||||
# FEATURES AND LIMITATIONS #
|
||||
|
||||
<ul>
|
||||
<li>Uses the VpnService API featured by Android 4+. Devices by some manufacturers seem to lack support for this - strongSwan VPN Client won't work on these devices!</li>
|
||||
<li>Uses the IKEv2 key exchange protocol (IKEv1 is not supported)</li>
|
||||
<li>Uses IPsec for data traffic (L2TP is not supported)</li>
|
||||
<li>Full support for changed connectivity and mobility through MOBIKE (or reauthentication)</li>
|
||||
<li>Supports username/password EAP authentication (namely EAP-MSCHAPv2, EAP-MD5 and EAP-GTC) as well as RSA/ECDSA private key/certificate authentication to authenticate users, EAP-TLS with client certificates is also supported</li>
|
||||
<li>Combined RSA/ECDSA and EAP authentication is supported by using two authentication rounds as defined in RFC 4739</li>
|
||||
<li>VPN server certificates are verified against the CA certificates pre-installed or installed by the user on the system. The CA or server certificates used to authenticate the server can also be imported directly into the app.</li>
|
||||
<li>IKEv2 fragmentation is supported if the VPN server supports it (strongSwan does so since 5.2.1)</li>
|
||||
<li>Split-tunneling allows sending only certain traffic through the VPN and/or excluding specific traffic from it</li>
|
||||
<li>Per-app VPN allows limiting the VPN connection to specific apps, or exclude them from using it</li>
|
||||
<li>The IPsec implementation currently supports the AES-CBC, AES-GCM, ChaCha20/Poly1305 and SHA1/SHA2 algorithms</li>
|
||||
<li>Passwords are currently stored as cleartext in the database (only if stored with a profile)</li>
|
||||
<li>VPN profiles may be imported from files</li>
|
||||
</ul>
|
||||
|
||||
Details and a changelog can be found on our wiki: https://wiki.strongswan.org/projects/strongswan/wiki/AndroidVPNClient
|
||||
|
||||
# PERMISSIONS #
|
||||
|
||||
<ul>
|
||||
<li>READ_EXTERNAL_STORAGE: Allows importing VPN profiles and CA certificates from external storage on some Android versions</li>
|
||||
<li>QUERY_ALL_PACKAGES: Required on Android 11+ to select apps to ex-/include in VPN profiles and the optional EAP-TNC use case</li>
|
||||
</ul>
|
||||
|
||||
# EXAMPLE SERVER CONFIGURATION #
|
||||
|
||||
Example server configurations may be found on our wiki: https://wiki.strongswan.org/projects/strongswan/wiki/AndroidVPNClient#Server-Configuration
|
||||
|
||||
Please note that the host name (or IP address) configured with a VPN profile in the app *must be* contained in the server certificate as subjectAltName extension.
|
||||
|
||||
# FEEDBACK #
|
||||
|
||||
Please post bug reports and feature requests via GitHub: https://github.com/strongswan/strongswan/issues/new/choose
|
||||
If you do so, please include information about your device (manufacturer, model, OS version etc.).
|
||||
|
||||
The log file written by the key exchange service can be sent directly from within the application.
|
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
Binary file not shown.
After Width: | Height: | Size: 122 KiB |
Binary file not shown.
After Width: | Height: | Size: 107 KiB |
|
@ -0,0 +1 @@
|
|||
An easy to use IKEv2/IPsec-based VPN client.
|
|
@ -0,0 +1 @@
|
|||
strongSwan VPN Client
|
|
@ -0,0 +1,11 @@
|
|||
# 2.3.3 #
|
||||
|
||||
- Fügt einen Button zur Installation von Benutzer-Zertifikaten hinzu
|
||||
|
||||
# 2.3.2 #
|
||||
|
||||
- VPN Verbindungen nicht als getaktet markieren (der Default hat mit Android 10 als Ziel-SDK geändert)
|
||||
|
||||
# 2.3.1 #
|
||||
|
||||
- Optionale Verwendung von IPv6 Transport-Adressen für IKE und ESP. Benötigt Unterstützung für UDP Encapsulation für IPv6 auf dem Server (bei Linux erst seit 5.8 der Fall, viele Server bieten also noch keine Unterstützung)
|
|
@ -0,0 +1,11 @@
|
|||
# 2.3.3 #
|
||||
|
||||
- Adds a button to install user certificates
|
||||
|
||||
# 2.3.2 #
|
||||
|
||||
- Don't mark VPN connections as metered (the default changed when targeting Android 10 with the last release)
|
||||
|
||||
# 2.3.1 #
|
||||
|
||||
- Optionally use IPv6 transport addresses for IKE and ESP. Can only be enabled if the server supports UDP encapsulation for IPv6 (the Linux kernel only supports this since 5.8, so many servers will not support it yet)
|
|
@ -123,6 +123,14 @@
|
|||
android:id="@+id/select_user_certificate"
|
||||
layout="@layout/two_line_button" />
|
||||
|
||||
<Button
|
||||
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:text="@string/profile_user_certificate_install" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
|
@ -280,7 +288,7 @@
|
|||
|
||||
</org.strongswan.android.ui.widget.TextInputLayoutHelper>
|
||||
|
||||
<Switch
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/cert_req"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -297,7 +305,7 @@
|
|||
android:textSize="12sp"
|
||||
android:text="@string/profile_cert_req_hint" />
|
||||
|
||||
<Switch
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/use_ocsp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -314,7 +322,7 @@
|
|||
android:textSize="12sp"
|
||||
android:text="@string/profile_use_ocsp_hint" />
|
||||
|
||||
<Switch
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/use_crl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -331,7 +339,7 @@
|
|||
android:textSize="12sp"
|
||||
android:text="@string/profile_use_crl_hint" />
|
||||
|
||||
<Switch
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/strict_revocation"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -348,7 +356,7 @@
|
|||
android:textSize="12sp"
|
||||
android:text="@string/profile_strict_revocation_hint" />
|
||||
|
||||
<Switch
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/rsa_pss"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -365,7 +373,7 @@
|
|||
android:textSize="12sp"
|
||||
android:text="@string/profile_rsa_pss_hint" />
|
||||
|
||||
<Switch
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/ipv6_transport"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
app:tabGravity="fill"
|
||||
app:tabMode="fixed"/>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
<string name="profile_user_certificate_label">Benutzer-Zertifikat</string>
|
||||
<string name="profile_user_select_certificate_label">Benutzer-Zertifikat auswählen</string>
|
||||
<string name="profile_user_select_certificate">Wählen Sie ein bestimmtes Benutzer-Zertifikat</string>
|
||||
<string name="profile_user_certificate_install">Benutzer-Zertifikat installieren</string>
|
||||
<string name="profile_ca_label">CA-Zertifikat</string>
|
||||
<string name="profile_ca_auto_label">Automatisch wählen</string>
|
||||
<string name="profile_ca_select_certificate_label">CA-Zertifikat auswählen</string>
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
<string name="profile_user_certificate_label">Certyfikat użytkownika</string>
|
||||
<string name="profile_user_select_certificate_label">Wybierz certyfikat użytkownika</string>
|
||||
<string name="profile_user_select_certificate">>Wybierz określony certyfikat użytkownika</string>
|
||||
<string name="profile_user_certificate_install">Install user certificate</string>
|
||||
<string name="profile_ca_label">Certyfikat CA</string>
|
||||
<string name="profile_ca_auto_label">Wybierz automatycznie</string>
|
||||
<string name="profile_ca_select_certificate_label">Wybierz certyfikat CA</string>
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
<string name="profile_user_certificate_label">Сертификат пользователя</string>
|
||||
<string name="profile_user_select_certificate_label">Выбрать сертификат пользователя</string>
|
||||
<string name="profile_user_select_certificate">Выбрать сертификат пользователя</string>
|
||||
<string name="profile_user_certificate_install">Install user certificate</string>
|
||||
<string name="profile_ca_label">Сертификат CA</string>
|
||||
<string name="profile_ca_auto_label">Выбрать автоматически</string>
|
||||
<string name="profile_ca_select_certificate_label">Выбрать сертификат CA</string>
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
<string name="profile_user_certificate_label">Сертифікат користувача</string>
|
||||
<string name="profile_user_select_certificate_label">Виберіть сертифікат користувача</string>
|
||||
<string name="profile_user_select_certificate">Вибрати спеціальний сертифікат користувача</string>
|
||||
<string name="profile_user_certificate_install">Install user certificate</string>
|
||||
<string name="profile_ca_label">Сертифікат CA</string>
|
||||
<string name="profile_ca_auto_label">Вибрати автоматично</string>
|
||||
<string name="profile_ca_select_certificate_label">Вибрати сертифікат CA</string>
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
<string name="profile_user_certificate_label">用户证书</string>
|
||||
<string name="profile_user_select_certificate_label">选择用户证书</string>
|
||||
<string name="profile_user_select_certificate">选择指定的用户证书</string>
|
||||
<string name="profile_user_certificate_install">Install user certificate</string>
|
||||
<string name="profile_ca_label">CA证书</string>
|
||||
<string name="profile_ca_auto_label">自动选择</string>
|
||||
<string name="profile_ca_select_certificate_label">选择CA证书</string>
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
<string name="profile_user_certificate_label">用戶憑證</string>
|
||||
<string name="profile_user_select_certificate_label">選擇用戶憑證</string>
|
||||
<string name="profile_user_select_certificate">選擇指定的用戶憑證</string>
|
||||
<string name="profile_user_certificate_install">Install user certificate</string>
|
||||
<string name="profile_ca_label">CA憑證</string>
|
||||
<string name="profile_ca_auto_label">自動選擇</string>
|
||||
<string name="profile_ca_select_certificate_label">選擇CA憑證</string>
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
<string name="profile_user_certificate_label">User certificate</string>
|
||||
<string name="profile_user_select_certificate_label">Select user certificate</string>
|
||||
<string name="profile_user_select_certificate">Select a specific user certificate</string>
|
||||
<string name="profile_user_certificate_install">Install user certificate</string>
|
||||
<string name="profile_ca_label">CA certificate</string>
|
||||
<string name="profile_ca_auto_label">Select automatically</string>
|
||||
<string name="profile_ca_select_certificate_label">Select CA certificate</string>
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
||||
classpath 'com.android.tools.build:gradle:4.2.2'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
|
||||
|
|
|
@ -1323,7 +1323,7 @@ static void netlink_find_offload_feature(const char *ifname)
|
|||
{
|
||||
struct ethtool_sset_info *sset_info;
|
||||
struct ethtool_gstrings *cmd = NULL;
|
||||
struct ifreq ifr;
|
||||
struct ifreq ifr = { 0 };
|
||||
uint32_t sset_len, i;
|
||||
char *str;
|
||||
int err, query_socket;
|
||||
|
@ -1392,7 +1392,7 @@ static bool netlink_detect_offload(const char *ifname)
|
|||
{
|
||||
struct ethtool_gfeatures *cmd;
|
||||
uint32_t feature_bit;
|
||||
struct ifreq ifr;
|
||||
struct ifreq ifr = { 0 };
|
||||
int query_socket;
|
||||
int block;
|
||||
bool ret = FALSE;
|
||||
|
|
|
@ -143,7 +143,7 @@ if [ -z "$TARBALL" ]; then
|
|||
do_on_exit umount $LOOPDIR/root/strongswan
|
||||
|
||||
log_action "Determine strongSwan version"
|
||||
desc=`git -C $SWANDIR describe --dirty`
|
||||
desc=`git -C $SWANDIR describe --exclude 'android-*' --dirty`
|
||||
if [ $? -eq 0 ]; then
|
||||
version="$desc (`git -C $SWANDIR rev-parse --abbrev-ref HEAD`)"
|
||||
else
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
PKG = tkm-rpc
|
||||
SRC = https://git.codelabs.ch/git/$(PKG).git
|
||||
REV = a681aa8694412f16a44a7fba2eeb67cb3d43caf6
|
||||
REV = 85f725c0c938cc7f8a48ed86892d6b112b858b8b
|
||||
|
||||
PREFIX = /usr/local/ada
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
PKG = tkm
|
||||
SRC = https://git.codelabs.ch/git/$(PKG).git
|
||||
REV = fadff7fd8c454ae46177924fde56600081ddf4d5
|
||||
REV = e46eef9f0991ba2777dcde845c2e00b8df9c72f7
|
||||
|
||||
export ADA_PROJECT_PATH=/usr/local/ada/lib/gnat
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
PKG = wolfssl
|
||||
SRC = https://github.com/wolfSSL/$(PKG).git
|
||||
REV = 0caf3ba456f1 # v4.7.1r + SHA-3 fix
|
||||
REV = v4.8.0-stable
|
||||
|
||||
NUM_CPUS := $(shell getconf _NPROCESSORS_ONLN)
|
||||
|
||||
|
|
Loading…
Reference in New Issue