mirror of
https://github.com/nextcloud/android.git
synced 2024-12-19 15:33:00 +03:00
Merge remote-tracking branch 'origin/master' into dev
This commit is contained in:
commit
b21f0adecb
13 changed files with 250 additions and 243 deletions
|
@ -128,8 +128,6 @@ android {
|
||||||
testInstrumentationRunnerArgument "TEST_SERVER_PASSWORD", "${NC_TEST_SERVER_PASSWORD}"
|
testInstrumentationRunnerArgument "TEST_SERVER_PASSWORD", "${NC_TEST_SERVER_PASSWORD}"
|
||||||
testInstrumentationRunnerArguments disableAnalytics: 'true'
|
testInstrumentationRunnerArguments disableAnalytics: 'true'
|
||||||
|
|
||||||
multiDexEnabled true
|
|
||||||
|
|
||||||
versionCode versionMajor * 10000000 + versionMinor * 10000 + versionPatch * 100 + versionBuild
|
versionCode versionMajor * 10000000 + versionMinor * 10000 + versionPatch * 100 + versionBuild
|
||||||
|
|
||||||
if (versionBuild > 89) {
|
if (versionBuild > 89) {
|
||||||
|
@ -265,8 +263,6 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// dependencies for app building
|
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
|
||||||
implementation("com.github.nextcloud:android-library:$androidLibraryVersion") {
|
implementation("com.github.nextcloud:android-library:$androidLibraryVersion") {
|
||||||
exclude group: 'org.ogce', module: 'xpp3' // unused in Android and brings wrong Junit version
|
exclude group: 'org.ogce', module: 'xpp3' // unused in Android and brings wrong Junit version
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.nextcloud.common.NextcloudClient;
|
import com.nextcloud.common.NextcloudClient;
|
||||||
import com.owncloud.android.MainApp;
|
import com.owncloud.android.MainApp;
|
||||||
|
@ -52,10 +53,10 @@ public class UserAccountManagerImpl implements UserAccountManager {
|
||||||
private static final String PREF_SELECT_OC_ACCOUNT = "select_oc_account";
|
private static final String PREF_SELECT_OC_ACCOUNT = "select_oc_account";
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private AccountManager accountManager;
|
private final AccountManager accountManager;
|
||||||
|
|
||||||
public static UserAccountManagerImpl fromContext(Context context) {
|
public static UserAccountManagerImpl fromContext(Context context) {
|
||||||
AccountManager am = (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE);
|
AccountManager am = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
|
||||||
return new UserAccountManagerImpl(context, am);
|
return new UserAccountManagerImpl(context, am);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +182,12 @@ public class UserAccountManagerImpl implements UserAccountManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
OwnCloudAccount ownCloudAccount = null;
|
if (context == null) {
|
||||||
|
Log_OC.d(TAG, "Context is null MainApp.getAppContext() used");
|
||||||
|
context = MainApp.getAppContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
OwnCloudAccount ownCloudAccount;
|
||||||
try {
|
try {
|
||||||
ownCloudAccount = new OwnCloudAccount(account, context);
|
ownCloudAccount = new OwnCloudAccount(account, context);
|
||||||
} catch (AccountUtils.AccountNotFoundException ex) {
|
} catch (AccountUtils.AccountNotFoundException ex) {
|
||||||
|
|
|
@ -91,6 +91,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils;
|
||||||
import org.conscrypt.Conscrypt;
|
import org.conscrypt.Conscrypt;
|
||||||
import org.greenrobot.eventbus.EventBus;
|
import org.greenrobot.eventbus.EventBus;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
|
@ -114,7 +115,6 @@ import androidx.core.util.Pair;
|
||||||
import androidx.lifecycle.Lifecycle;
|
import androidx.lifecycle.Lifecycle;
|
||||||
import androidx.lifecycle.LifecycleEventObserver;
|
import androidx.lifecycle.LifecycleEventObserver;
|
||||||
import androidx.lifecycle.ProcessLifecycleOwner;
|
import androidx.lifecycle.ProcessLifecycleOwner;
|
||||||
import androidx.multidex.MultiDexApplication;
|
|
||||||
import dagger.android.AndroidInjector;
|
import dagger.android.AndroidInjector;
|
||||||
import dagger.android.DispatchingAndroidInjector;
|
import dagger.android.DispatchingAndroidInjector;
|
||||||
import dagger.android.HasAndroidInjector;
|
import dagger.android.HasAndroidInjector;
|
||||||
|
@ -129,14 +129,14 @@ import static com.owncloud.android.ui.activity.ContactsPreferenceActivity.PREFER
|
||||||
* Main Application of the project.
|
* Main Application of the project.
|
||||||
* Contains methods to build the "static" strings. These strings were before constants in different classes.
|
* Contains methods to build the "static" strings. These strings were before constants in different classes.
|
||||||
*/
|
*/
|
||||||
public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
public class MainApp extends Application implements HasAndroidInjector {
|
||||||
public static final OwnCloudVersion OUTDATED_SERVER_VERSION = NextcloudVersion.nextcloud_26;
|
public static final OwnCloudVersion OUTDATED_SERVER_VERSION = NextcloudVersion.nextcloud_26;
|
||||||
public static final OwnCloudVersion MINIMUM_SUPPORTED_SERVER_VERSION = OwnCloudVersion.nextcloud_16;
|
public static final OwnCloudVersion MINIMUM_SUPPORTED_SERVER_VERSION = OwnCloudVersion.nextcloud_16;
|
||||||
|
|
||||||
private static final String TAG = MainApp.class.getSimpleName();
|
private static final String TAG = MainApp.class.getSimpleName();
|
||||||
public static final String DOT = ".";
|
public static final String DOT = ".";
|
||||||
|
|
||||||
private static Context mContext;
|
private static WeakReference<Context> appContext;
|
||||||
|
|
||||||
private static String storagePath;
|
private static String storagePath;
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
||||||
* Temporary hack
|
* Temporary hack
|
||||||
*/
|
*/
|
||||||
private static void initGlobalContext(Context context) {
|
private static void initGlobalContext(Context context) {
|
||||||
mContext = context;
|
appContext = new WeakReference<>(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -491,7 +491,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void initContactsBackup(UserAccountManager accountManager, BackgroundJobManager backgroundJobManager) {
|
public static void initContactsBackup(UserAccountManager accountManager, BackgroundJobManager backgroundJobManager) {
|
||||||
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(mContext);
|
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(appContext.get());
|
||||||
List<User> users = accountManager.getAllUsers();
|
List<User> users = accountManager.getAllUsers();
|
||||||
for (User user : users) {
|
for (User user : users) {
|
||||||
if (arbitraryDataProvider.getBooleanValue(user, PREFERENCE_CONTACTS_AUTOMATIC_BACKUP)) {
|
if (arbitraryDataProvider.getBooleanValue(user, PREFERENCE_CONTACTS_AUTOMATIC_BACKUP)) {
|
||||||
|
@ -609,7 +609,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
||||||
preferences.setAutoUploadInit(true);
|
preferences.setAutoUploadInit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
FilesSyncHelper.scheduleFilesSyncForAllFoldersIfNeeded(mContext, syncedFolderProvider, backgroundJobManager);
|
FilesSyncHelper.scheduleFilesSyncForAllFoldersIfNeeded(appContext.get(), syncedFolderProvider, backgroundJobManager);
|
||||||
FilesSyncHelper.restartUploadsIfNeeded(
|
FilesSyncHelper.restartUploadsIfNeeded(
|
||||||
uploadsStorageManager,
|
uploadsStorageManager,
|
||||||
accountManager,
|
accountManager,
|
||||||
|
@ -705,11 +705,11 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Context getAppContext() {
|
public static Context getAppContext() {
|
||||||
return MainApp.mContext;
|
return MainApp.appContext.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setAppContext(Context context) {
|
public static void setAppContext(Context context) {
|
||||||
MainApp.mContext = context;
|
MainApp.appContext = new WeakReference<>(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getStoragePath() {
|
public static String getStoragePath() {
|
||||||
|
@ -831,7 +831,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
||||||
if (!preferences.isAutoUploadPathsUpdateEnabled()) {
|
if (!preferences.isAutoUploadPathsUpdateEnabled()) {
|
||||||
SyncedFolderProvider syncedFolderProvider =
|
SyncedFolderProvider syncedFolderProvider =
|
||||||
new SyncedFolderProvider(MainApp.getAppContext().getContentResolver(), preferences, clock);
|
new SyncedFolderProvider(MainApp.getAppContext().getContentResolver(), preferences, clock);
|
||||||
syncedFolderProvider.updateAutoUploadPaths(mContext);
|
syncedFolderProvider.updateAutoUploadPaths(appContext.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -804,7 +804,8 @@ public class ReceiveExternalFilesActivity extends FileActivity
|
||||||
|
|
||||||
private void startSyncFolderOperation(OCFile folder) {
|
private void startSyncFolderOperation(OCFile folder) {
|
||||||
if (folder == null) {
|
if (folder == null) {
|
||||||
throw new IllegalArgumentException("Folder must not be null");
|
DisplayUtils.showSnackMessage(this, R.string.receive_external_files_activity_start_sync_folder_is_not_exists_message);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long currentSyncTime = System.currentTimeMillis();
|
long currentSyncTime = System.currentTimeMillis();
|
||||||
|
|
|
@ -16,18 +16,20 @@ import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding;
|
||||||
import com.owncloud.android.lib.common.network.CertificateCombinedException;
|
import com.owncloud.android.lib.common.network.CertificateCombinedException;
|
||||||
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
|
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
public class CertificateCombinedExceptionViewAdapter implements SslUntrustedCertDialog.ErrorViewAdapter {
|
public class CertificateCombinedExceptionViewAdapter implements SslUntrustedCertDialog.ErrorViewAdapter {
|
||||||
|
|
||||||
//private final static String TAG = CertificateCombinedExceptionViewAdapter.class.getSimpleName();
|
//private final static String TAG = CertificateCombinedExceptionViewAdapter.class.getSimpleName();
|
||||||
|
|
||||||
private CertificateCombinedException mSslException;
|
private final CertificateCombinedException mSslException;
|
||||||
|
|
||||||
public CertificateCombinedExceptionViewAdapter(CertificateCombinedException sslException) {
|
public CertificateCombinedExceptionViewAdapter(CertificateCombinedException sslException) {
|
||||||
mSslException = sslException;
|
mSslException = sslException;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateErrorView(SslUntrustedCertLayoutBinding binding) {
|
public void updateErrorView(@NonNull SslUntrustedCertLayoutBinding binding) {
|
||||||
/// clean
|
/// clean
|
||||||
binding.reasonNoInfoAboutError.setVisibility(View.GONE);
|
binding.reasonNoInfoAboutError.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class SslCertificateViewAdapter implements SslUntrustedCertDialog.Certifi
|
||||||
|
|
||||||
//private final static String TAG = SslCertificateViewAdapter.class.getSimpleName();
|
//private final static String TAG = SslCertificateViewAdapter.class.getSimpleName();
|
||||||
|
|
||||||
private SslCertificate mCertificate;
|
private final SslCertificate mCertificate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -36,7 +36,7 @@ public class SslCertificateViewAdapter implements SslUntrustedCertDialog.Certifi
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateCertificateView(SslUntrustedCertLayoutBinding binding) {
|
public void updateCertificateView(@NonNull SslUntrustedCertLayoutBinding binding) {
|
||||||
if (mCertificate != null) {
|
if (mCertificate != null) {
|
||||||
binding.nullCert.setVisibility(View.GONE);
|
binding.nullCert.setVisibility(View.GONE);
|
||||||
showSubject(mCertificate.getIssuedTo(), binding);
|
showSubject(mCertificate.getIssuedTo(), binding);
|
||||||
|
|
|
@ -14,6 +14,8 @@ import android.view.View;
|
||||||
import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding;
|
import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding;
|
||||||
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
|
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog to show an Untrusted Certificate
|
* Dialog to show an Untrusted Certificate
|
||||||
*/
|
*/
|
||||||
|
@ -21,14 +23,14 @@ public class SslErrorViewAdapter implements SslUntrustedCertDialog.ErrorViewAdap
|
||||||
|
|
||||||
//private final static String TAG = SslErrorViewAdapter.class.getSimpleName();
|
//private final static String TAG = SslErrorViewAdapter.class.getSimpleName();
|
||||||
|
|
||||||
private SslError mSslError;
|
private final SslError mSslError;
|
||||||
|
|
||||||
public SslErrorViewAdapter(SslError sslError) {
|
public SslErrorViewAdapter(SslError sslError) {
|
||||||
mSslError = sslError;
|
mSslError = sslError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateErrorView(SslUntrustedCertLayoutBinding binding) {
|
public void updateErrorView(@NonNull SslUntrustedCertLayoutBinding binding) {
|
||||||
/// clean
|
/// clean
|
||||||
binding.reasonNoInfoAboutError.setVisibility(View.GONE);
|
binding.reasonNoInfoAboutError.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ import androidx.annotation.NonNull;
|
||||||
*/
|
*/
|
||||||
public class X509CertificateViewAdapter implements SslUntrustedCertDialog.CertificateViewAdapter {
|
public class X509CertificateViewAdapter implements SslUntrustedCertDialog.CertificateViewAdapter {
|
||||||
|
|
||||||
private X509Certificate mCertificate;
|
private final X509Certificate mCertificate;
|
||||||
|
|
||||||
private static final String TAG = X509CertificateViewAdapter.class.getSimpleName();
|
private static final String TAG = X509CertificateViewAdapter.class.getSimpleName();
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ public class X509CertificateViewAdapter implements SslUntrustedCertDialog.Certif
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateCertificateView(SslUntrustedCertLayoutBinding binding) {
|
public void updateCertificateView(@NonNull SslUntrustedCertLayoutBinding binding) {
|
||||||
if (mCertificate != null) {
|
if (mCertificate != null) {
|
||||||
binding.nullCert.setVisibility(View.GONE);
|
binding.nullCert.setVisibility(View.GONE);
|
||||||
showSubject(mCertificate.getSubjectX500Principal(), binding);
|
showSubject(mCertificate.getSubjectX500Principal(), binding);
|
||||||
|
@ -97,7 +97,7 @@ public class X509CertificateViewAdapter implements SslUntrustedCertDialog.Certif
|
||||||
|
|
||||||
private String getDigestHexBytesWithColonsAndNewLines(Context context, final String digestType, final byte [] cert) {
|
private String getDigestHexBytesWithColonsAndNewLines(Context context, final String digestType, final byte [] cert) {
|
||||||
final byte[] rawDigest;
|
final byte[] rawDigest;
|
||||||
final String newLine = System.getProperty("line.separator");
|
final String newLine = System.lineSeparator();
|
||||||
|
|
||||||
rawDigest = getDigest(digestType, cert);
|
rawDigest = getDigest(digestType, cert);
|
||||||
|
|
||||||
|
|
|
@ -1,215 +0,0 @@
|
||||||
/*
|
|
||||||
* Nextcloud - Android Client
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
|
||||||
* SPDX-FileCopyrightText: 2018-2022 Andy Scherzinger <info@andy-scherzinger.de>
|
|
||||||
* SPDX-FileCopyrightText: 2020 Stefan Niedermann <info@niedermann.it>
|
|
||||||
* SPDX-FileCopyrightText: 2018 Tobias Kaminsky <tobias@kaminsky.me>
|
|
||||||
* SPDX-FileCopyrightText: 2015 ownCloud Inc.
|
|
||||||
* SPDX-FileCopyrightText: 2014 David A. Velasco <dvelasco@solidgear.es>
|
|
||||||
* SPDX-FileCopyrightText: 2014 María Asensio Valverde <masensio@solidgear.es>
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only)
|
|
||||||
*/
|
|
||||||
package com.owncloud.android.ui.dialog;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.net.http.SslError;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.webkit.SslErrorHandler;
|
|
||||||
import android.widget.Button;
|
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
||||||
import com.nextcloud.client.di.Injectable;
|
|
||||||
import com.owncloud.android.R;
|
|
||||||
import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding;
|
|
||||||
import com.owncloud.android.lib.common.network.CertificateCombinedException;
|
|
||||||
import com.owncloud.android.lib.common.network.NetworkUtils;
|
|
||||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
|
||||||
import com.owncloud.android.ui.adapter.CertificateCombinedExceptionViewAdapter;
|
|
||||||
import com.owncloud.android.ui.adapter.SslCertificateViewAdapter;
|
|
||||||
import com.owncloud.android.ui.adapter.SslErrorViewAdapter;
|
|
||||||
import com.owncloud.android.ui.adapter.X509CertificateViewAdapter;
|
|
||||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.fragment.app.DialogFragment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dialog to show information about an untrusted certificate and allow the user to decide trust on it or not.
|
|
||||||
* Abstract implementation of common functionality for different dialogs that get the information about the error and
|
|
||||||
* the certificate from different classes.
|
|
||||||
*/
|
|
||||||
public class SslUntrustedCertDialog extends DialogFragment implements Injectable {
|
|
||||||
|
|
||||||
private final static String TAG = SslUntrustedCertDialog.class.getSimpleName();
|
|
||||||
|
|
||||||
@Inject ViewThemeUtils viewThemeUtils;
|
|
||||||
|
|
||||||
protected SslUntrustedCertLayoutBinding binding;
|
|
||||||
protected SslErrorHandler mHandler;
|
|
||||||
protected X509Certificate m509Certificate;
|
|
||||||
|
|
||||||
private ErrorViewAdapter mErrorViewAdapter;
|
|
||||||
private CertificateViewAdapter mCertificateViewAdapter;
|
|
||||||
|
|
||||||
public static SslUntrustedCertDialog newInstanceForEmptySslError(SslError error, SslErrorHandler handler) {
|
|
||||||
if (error == null) {
|
|
||||||
throw new IllegalArgumentException("Trying to create instance with parameter error == null");
|
|
||||||
}
|
|
||||||
if (handler == null) {
|
|
||||||
throw new IllegalArgumentException("Trying to create instance with parameter handler == null");
|
|
||||||
}
|
|
||||||
SslUntrustedCertDialog dialog = new SslUntrustedCertDialog();
|
|
||||||
dialog.mHandler = handler;
|
|
||||||
dialog.mErrorViewAdapter = new SslErrorViewAdapter(error);
|
|
||||||
dialog.mCertificateViewAdapter = new SslCertificateViewAdapter(error.getCertificate());
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SslUntrustedCertDialog newInstanceForFullSslError(CertificateCombinedException sslException) {
|
|
||||||
if (sslException == null) {
|
|
||||||
throw new IllegalArgumentException("Trying to create instance with parameter sslException == null");
|
|
||||||
}
|
|
||||||
SslUntrustedCertDialog dialog = new SslUntrustedCertDialog();
|
|
||||||
dialog.m509Certificate = sslException.getServerCertificate();
|
|
||||||
dialog.mErrorViewAdapter = new CertificateCombinedExceptionViewAdapter(sslException);
|
|
||||||
dialog.mCertificateViewAdapter = new X509CertificateViewAdapter(sslException.getServerCertificate());
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SslUntrustedCertDialog newInstanceForFullSslError(X509Certificate cert, SslError error, SslErrorHandler handler) {
|
|
||||||
if (cert == null) {
|
|
||||||
throw new IllegalArgumentException("Trying to create instance with parameter cert == null");
|
|
||||||
}
|
|
||||||
if (error == null) {
|
|
||||||
throw new IllegalArgumentException("Trying to create instance with parameter error == null");
|
|
||||||
}
|
|
||||||
if (handler == null) {
|
|
||||||
throw new IllegalArgumentException("Trying to create instance with parameter handler == null");
|
|
||||||
}
|
|
||||||
SslUntrustedCertDialog dialog = new SslUntrustedCertDialog();
|
|
||||||
dialog.m509Certificate = cert;
|
|
||||||
dialog.mHandler = handler;
|
|
||||||
dialog.mErrorViewAdapter = new SslErrorViewAdapter(error);
|
|
||||||
dialog.mCertificateViewAdapter = new X509CertificateViewAdapter(cert);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(@NonNull Activity activity) {
|
|
||||||
Log_OC.d(TAG, "onAttach");
|
|
||||||
super.onAttach(activity);
|
|
||||||
if (!(activity instanceof OnSslUntrustedCertListener)) {
|
|
||||||
throw new IllegalArgumentException("The host activity must implement " + OnSslUntrustedCertListener.class.getCanonicalName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
Log_OC.d(TAG, "onCreate, savedInstanceState is " + savedInstanceState);
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setRetainInstance(true); // force to keep the state of the fragment on configuration changes (such as device rotations)
|
|
||||||
setCancelable(false);
|
|
||||||
binding = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
Log_OC.d(TAG, "onCreateDialog, savedInstanceState is " + savedInstanceState);
|
|
||||||
|
|
||||||
binding = SslUntrustedCertLayoutBinding.inflate(getLayoutInflater(), null, false);
|
|
||||||
binding.detailsScroll.setVisibility(View.GONE);
|
|
||||||
mErrorViewAdapter.updateErrorView(binding);
|
|
||||||
|
|
||||||
binding.ok.setOnClickListener(new OnCertificateTrusted());
|
|
||||||
|
|
||||||
binding.cancel.setOnClickListener(new OnCertificateNotTrusted());
|
|
||||||
|
|
||||||
binding.detailsBtn.setOnClickListener(v -> {
|
|
||||||
if (binding.detailsScroll.getVisibility() == View.VISIBLE) {
|
|
||||||
binding.detailsScroll.setVisibility(View.GONE);
|
|
||||||
((Button) v).setText(R.string.ssl_validator_btn_details_see);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
binding.detailsScroll.setVisibility(View.VISIBLE);
|
|
||||||
((Button) v).setText(R.string.ssl_validator_btn_details_hide);
|
|
||||||
mCertificateViewAdapter.updateCertificateView(binding);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(binding.getRoot().getContext());
|
|
||||||
builder.setView(binding.getRoot());
|
|
||||||
|
|
||||||
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.getRoot().getContext(), builder);
|
|
||||||
|
|
||||||
final Dialog dialog = builder.create();
|
|
||||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView() {
|
|
||||||
Log_OC.d(TAG, "onDestroyView");
|
|
||||||
if (getDialog() != null && getRetainInstance()) {
|
|
||||||
getDialog().setDismissMessage(null);
|
|
||||||
}
|
|
||||||
super.onDestroyView();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class OnCertificateNotTrusted implements OnClickListener {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
getDialog().cancel();
|
|
||||||
if (mHandler != null) {
|
|
||||||
mHandler.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class OnCertificateTrusted implements OnClickListener {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
dismiss();
|
|
||||||
if (mHandler != null) {
|
|
||||||
mHandler.proceed();
|
|
||||||
}
|
|
||||||
if (m509Certificate != null) {
|
|
||||||
Activity activity = getActivity();
|
|
||||||
try {
|
|
||||||
NetworkUtils.addCertToKnownServersStore(m509Certificate, activity); // TODO make this asynchronously, it can take some time
|
|
||||||
((OnSslUntrustedCertListener)activity).onSavedCertificate();
|
|
||||||
} catch (GeneralSecurityException | IOException e) {
|
|
||||||
((OnSslUntrustedCertListener)activity).onFailedSavingCertificate();
|
|
||||||
Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnSslUntrustedCertListener {
|
|
||||||
void onSavedCertificate();
|
|
||||||
void onFailedSavingCertificate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ErrorViewAdapter {
|
|
||||||
void updateErrorView(SslUntrustedCertLayoutBinding binding);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface CertificateViewAdapter {
|
|
||||||
void updateCertificateView(SslUntrustedCertLayoutBinding binding);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
/*
|
||||||
|
* Nextcloud - Android Client
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
|
||||||
|
* SPDX-FileCopyrightText: 2018-2022 Andy Scherzinger <info@andy-scherzinger.de>
|
||||||
|
* SPDX-FileCopyrightText: 2020 Stefan Niedermann <info@niedermann.it>
|
||||||
|
* SPDX-FileCopyrightText: 2018 Tobias Kaminsky <tobias@kaminsky.me>
|
||||||
|
* SPDX-FileCopyrightText: 2015 ownCloud Inc.
|
||||||
|
* SPDX-FileCopyrightText: 2014 David A. Velasco <dvelasco@solidgear.es>
|
||||||
|
* SPDX-FileCopyrightText: 2014 María Asensio Valverde <masensio@solidgear.es>
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only)
|
||||||
|
*/
|
||||||
|
package com.owncloud.android.ui.dialog
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.http.SslError
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.view.Window
|
||||||
|
import android.webkit.SslErrorHandler
|
||||||
|
import android.widget.Button
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.nextcloud.client.di.Injectable
|
||||||
|
import com.owncloud.android.R
|
||||||
|
import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding
|
||||||
|
import com.owncloud.android.lib.common.network.CertificateCombinedException
|
||||||
|
import com.owncloud.android.lib.common.network.NetworkUtils
|
||||||
|
import com.owncloud.android.lib.common.utils.Log_OC
|
||||||
|
import com.owncloud.android.ui.adapter.CertificateCombinedExceptionViewAdapter
|
||||||
|
import com.owncloud.android.ui.adapter.SslCertificateViewAdapter
|
||||||
|
import com.owncloud.android.ui.adapter.SslErrorViewAdapter
|
||||||
|
import com.owncloud.android.ui.adapter.X509CertificateViewAdapter
|
||||||
|
import com.owncloud.android.utils.theme.ViewThemeUtils
|
||||||
|
import java.io.IOException
|
||||||
|
import java.security.GeneralSecurityException
|
||||||
|
import java.security.cert.X509Certificate
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dialog to show information about an untrusted certificate and allow the user to decide trust on it or not.
|
||||||
|
* Abstract implementation of common functionality for different dialogs that get the information about the error and
|
||||||
|
* the certificate from different classes.
|
||||||
|
*/
|
||||||
|
open class SslUntrustedCertDialog : DialogFragment(), Injectable {
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
@Inject
|
||||||
|
var viewThemeUtils: ViewThemeUtils? = null
|
||||||
|
|
||||||
|
protected var binding: SslUntrustedCertLayoutBinding? = null
|
||||||
|
protected var sslErrorHandler: SslErrorHandler? = null
|
||||||
|
protected var x509Certificate: X509Certificate? = null
|
||||||
|
private var errorViewAdapter: ErrorViewAdapter? = null
|
||||||
|
private var certificateViewAdapter: CertificateViewAdapter? = null
|
||||||
|
|
||||||
|
override fun onAttach(context: Context) {
|
||||||
|
Log_OC.d(TAG, "onAttach")
|
||||||
|
super.onAttach(context)
|
||||||
|
require(activity is OnSslUntrustedCertListener) {
|
||||||
|
"The host activity must implement " + OnSslUntrustedCertListener::class.java.canonicalName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
Log_OC.d(TAG, "onCreate, savedInstanceState is $savedInstanceState")
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
// force to keep the state of the fragment on configuration changes (such as device rotations)
|
||||||
|
retainInstance = true
|
||||||
|
isCancelable = false
|
||||||
|
binding = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
Log_OC.d(TAG, "onCreateDialog, savedInstanceState is $savedInstanceState")
|
||||||
|
|
||||||
|
val layoutBinding = SslUntrustedCertLayoutBinding.inflate(layoutInflater, null, false)
|
||||||
|
this.binding = layoutBinding
|
||||||
|
|
||||||
|
layoutBinding.run {
|
||||||
|
detailsScroll.visibility = View.GONE
|
||||||
|
errorViewAdapter?.updateErrorView(layoutBinding)
|
||||||
|
|
||||||
|
ok.setOnClickListener(OnCertificateTrusted())
|
||||||
|
|
||||||
|
cancel.setOnClickListener(OnCertificateNotTrusted())
|
||||||
|
|
||||||
|
detailsBtn.setOnClickListener { v: View ->
|
||||||
|
if (detailsScroll.visibility == View.VISIBLE) {
|
||||||
|
detailsScroll.visibility = View.GONE
|
||||||
|
(v as Button).setText(R.string.ssl_validator_btn_details_see)
|
||||||
|
} else {
|
||||||
|
detailsScroll.visibility = View.VISIBLE
|
||||||
|
(v as Button).setText(R.string.ssl_validator_btn_details_hide)
|
||||||
|
certificateViewAdapter?.updateCertificateView(layoutBinding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val builder = MaterialAlertDialogBuilder(requireContext()).apply {
|
||||||
|
setView(layoutBinding.getRoot())
|
||||||
|
}
|
||||||
|
|
||||||
|
viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder)
|
||||||
|
|
||||||
|
return builder.create().apply {
|
||||||
|
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
Log_OC.d(TAG, "onDestroyView")
|
||||||
|
if (retainInstance) {
|
||||||
|
dialog?.setDismissMessage(null)
|
||||||
|
}
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class OnCertificateNotTrusted : View.OnClickListener {
|
||||||
|
override fun onClick(v: View) {
|
||||||
|
dialog?.cancel()
|
||||||
|
sslErrorHandler?.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class OnCertificateTrusted : View.OnClickListener {
|
||||||
|
override fun onClick(v: View) {
|
||||||
|
dismiss()
|
||||||
|
sslErrorHandler?.proceed()
|
||||||
|
|
||||||
|
if (x509Certificate == null) {
|
||||||
|
Log_OC.d(TAG, "m509Certificate is null onClick dismissed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activity == null) {
|
||||||
|
Log_OC.d(TAG, "activity is null onClick dismissed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// TODO make this asynchronously, it can take some time
|
||||||
|
NetworkUtils.addCertToKnownServersStore(x509Certificate, activity)
|
||||||
|
(activity as OnSslUntrustedCertListener?)?.onSavedCertificate()
|
||||||
|
} catch (e: GeneralSecurityException) {
|
||||||
|
(activity as OnSslUntrustedCertListener?)?.onFailedSavingCertificate()
|
||||||
|
Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
(activity as OnSslUntrustedCertListener?)?.onFailedSavingCertificate()
|
||||||
|
Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnSslUntrustedCertListener {
|
||||||
|
fun onSavedCertificate()
|
||||||
|
fun onFailedSavingCertificate()
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ErrorViewAdapter {
|
||||||
|
fun updateErrorView(binding: SslUntrustedCertLayoutBinding)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CertificateViewAdapter {
|
||||||
|
fun updateCertificateView(binding: SslUntrustedCertLayoutBinding)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG: String = SslUntrustedCertDialog::class.java.simpleName
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun newInstanceForEmptySslError(error: SslError?, handler: SslErrorHandler?): SslUntrustedCertDialog {
|
||||||
|
requireNotNull(error) { "Trying to create instance with parameter error == null" }
|
||||||
|
requireNotNull(handler) { "Trying to create instance with parameter handler == null" }
|
||||||
|
|
||||||
|
return SslUntrustedCertDialog().apply {
|
||||||
|
sslErrorHandler = handler
|
||||||
|
errorViewAdapter = SslErrorViewAdapter(error)
|
||||||
|
certificateViewAdapter = SslCertificateViewAdapter(error.certificate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun newInstanceForFullSslError(sslException: CertificateCombinedException?): SslUntrustedCertDialog {
|
||||||
|
requireNotNull(sslException) { "Trying to create instance with parameter sslException == null" }
|
||||||
|
|
||||||
|
return SslUntrustedCertDialog().apply {
|
||||||
|
x509Certificate = sslException.serverCertificate
|
||||||
|
errorViewAdapter = CertificateCombinedExceptionViewAdapter(sslException)
|
||||||
|
certificateViewAdapter = X509CertificateViewAdapter(sslException.serverCertificate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun newInstanceForFullSslError(
|
||||||
|
cert: X509Certificate?,
|
||||||
|
error: SslError?,
|
||||||
|
handler: SslErrorHandler?
|
||||||
|
): SslUntrustedCertDialog {
|
||||||
|
requireNotNull(cert) { "Trying to create instance with parameter cert == null" }
|
||||||
|
requireNotNull(error) { "Trying to create instance with parameter error == null" }
|
||||||
|
requireNotNull(handler) { "Trying to create instance with parameter handler == null" }
|
||||||
|
|
||||||
|
return SslUntrustedCertDialog().apply {
|
||||||
|
x509Certificate = cert
|
||||||
|
sslErrorHandler = handler
|
||||||
|
errorViewAdapter = SslErrorViewAdapter(error)
|
||||||
|
certificateViewAdapter = X509CertificateViewAdapter(cert)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -484,7 +484,7 @@
|
||||||
<string name="upload_files">Augšupielādē datnes</string>
|
<string name="upload_files">Augšupielādē datnes</string>
|
||||||
<string name="upload_list_delete">Dzēst</string>
|
<string name="upload_list_delete">Dzēst</string>
|
||||||
<string name="upload_list_empty_headline">Augšupielādes nav pieejamas.</string>
|
<string name="upload_list_empty_headline">Augšupielādes nav pieejamas.</string>
|
||||||
<string name="upload_list_empty_text_auto_upload">Augšupielādē kaut ko vai ieslēdz automātisko augšupielādi.</string>
|
<string name="upload_list_empty_text_auto_upload">Augšupielādē kaut ko vai ieslēdz automātisko augšupielādi!</string>
|
||||||
<string name="upload_query_move_foreign_files">Nepietiekama atmiņa neatļauj izvēlētās datnes kopēt uz %1$s mapi. Vai jūs gribat tās tur pārvietot?</string>
|
<string name="upload_query_move_foreign_files">Nepietiekama atmiņa neatļauj izvēlētās datnes kopēt uz %1$s mapi. Vai jūs gribat tās tur pārvietot?</string>
|
||||||
<string name="upload_unknown_error">Nezināma kļūda</string>
|
<string name="upload_unknown_error">Nezināma kļūda</string>
|
||||||
<string name="uploader_btn_alternative_text">Izvēlies</string>
|
<string name="uploader_btn_alternative_text">Izvēlies</string>
|
||||||
|
|
|
@ -448,6 +448,8 @@
|
||||||
<string name="clipboard_unexpected_error">Unexpected error while copying to clipboard</string>
|
<string name="clipboard_unexpected_error">Unexpected error while copying to clipboard</string>
|
||||||
<string name="clipboard_label">Text copied from %1$s</string>
|
<string name="clipboard_label">Text copied from %1$s</string>
|
||||||
|
|
||||||
|
<string name="receive_external_files_activity_start_sync_folder_is_not_exists_message">Folder cannot be found, sync operation is cancelled</string>
|
||||||
|
|
||||||
<string name="error_cant_bind_to_operations_service">Critical error: Unable to perform operations</string>
|
<string name="error_cant_bind_to_operations_service">Critical error: Unable to perform operations</string>
|
||||||
|
|
||||||
<string name="network_error_socket_exception">An error occurred during connection to the server</string>
|
<string name="network_error_socket_exception">An error occurred during connection to the server</string>
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
DO NOT TOUCH; GENERATED BY DRONE
|
DO NOT TOUCH; GENERATED BY DRONE
|
||||||
<span class="mdl-layout-title">Lint Report: 3 errors and 70 warnings</span>
|
<span class="mdl-layout-title">Lint Report: 3 errors and 69 warnings</span>
|
||||||
|
|
Loading…
Reference in a new issue