mirror of
https://github.com/nextcloud/android.git
synced 2024-11-24 06:05:42 +03:00
Merge pull request #2381 from nextcloud/showMnemonicBasedOnDeviceCredentials
Show mnemonic based on device credentials
This commit is contained in:
commit
d54b666d02
6 changed files with 101 additions and 27 deletions
|
@ -47,6 +47,7 @@ import android.support.annotation.LayoutRes;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.res.ResourcesCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatDelegate;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
@ -60,6 +61,7 @@ import com.owncloud.android.BuildConfig;
|
|||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.authentication.PassCodeManager;
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProvider;
|
||||
import com.owncloud.android.datamodel.ExternalLinksProvider;
|
||||
import com.owncloud.android.datastorage.DataStorageProvider;
|
||||
|
@ -71,6 +73,7 @@ import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
|
|||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.utils.DeviceCredentialUtils;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.EncryptionUtils;
|
||||
import com.owncloud.android.utils.MimeTypeUtil;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
|
||||
|
@ -119,6 +122,9 @@ public class Preferences extends PreferenceActivity
|
|||
private String mStoragePath;
|
||||
private String pendingLock;
|
||||
|
||||
private Account mAccount;
|
||||
private ArbitraryDataProvider mArbitraryDataProvider;
|
||||
|
||||
public static class PreferenceKeys {
|
||||
public static final String STORAGE_PATH = "storage_path";
|
||||
public static final String INSTANT_UPLOAD_PATH = "instant_upload_path";
|
||||
|
@ -150,6 +156,9 @@ public class Preferences extends PreferenceActivity
|
|||
String appVersion = getAppVersion();
|
||||
PreferenceScreen preferenceScreen = (PreferenceScreen) findPreference("preference_screen");
|
||||
|
||||
mAccount = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
|
||||
mArbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
|
||||
|
||||
// General
|
||||
setupGeneralCategory(accentColor);
|
||||
|
||||
|
@ -307,6 +316,8 @@ public class Preferences extends PreferenceActivity
|
|||
|
||||
setupContactsBackupPreference(preferenceCategoryMore);
|
||||
|
||||
setupE2EMnemonicPreference(preferenceCategoryMore);
|
||||
|
||||
setupHelpPreference(preferenceCategoryMore);
|
||||
|
||||
setupRecommendPreference(preferenceCategoryMore);
|
||||
|
@ -437,6 +448,34 @@ public class Preferences extends PreferenceActivity
|
|||
}
|
||||
}
|
||||
|
||||
private void setupE2EMnemonicPreference(PreferenceCategory preferenceCategoryMore) {
|
||||
String mnemonic = mArbitraryDataProvider.getValue(mAccount.name, EncryptionUtils.MNEMONIC);
|
||||
|
||||
Preference pMnemonic = findPreference("mnemonic");
|
||||
if (pMnemonic != null) {
|
||||
if (!mnemonic.isEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (DeviceCredentialUtils.areCredentialsAvailable(this)) {
|
||||
pMnemonic.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
|
||||
Intent i = new Intent(MainApp.getAppContext(), RequestCredentialsActivity.class);
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
Preferences.this.startActivityForResult(i, PassCodeManager.PASSCODE_ACTIVITY);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
pMnemonic.setEnabled(false);
|
||||
pMnemonic.setSummary(R.string.prefs_e2e_no_device_credentials);
|
||||
}
|
||||
} else {
|
||||
preferenceCategoryMore.removePreference(pMnemonic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupHelpPreference(PreferenceCategory preferenceCategoryMore) {
|
||||
boolean helpEnabled = getResources().getBoolean(R.bool.help_enabled);
|
||||
Preference pHelp = findPreference("help");
|
||||
|
@ -645,16 +684,15 @@ public class Preferences extends PreferenceActivity
|
|||
} else {
|
||||
// Upload on WiFi
|
||||
final ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
|
||||
final Account account = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
|
||||
|
||||
final SwitchPreference pUploadOnWifiCheckbox = (SwitchPreference) findPreference("synced_folder_on_wifi");
|
||||
pUploadOnWifiCheckbox.setChecked(
|
||||
arbitraryDataProvider.getBooleanValue(account, SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI));
|
||||
arbitraryDataProvider.getBooleanValue(mAccount, SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI));
|
||||
|
||||
pUploadOnWifiCheckbox.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
arbitraryDataProvider.storeOrUpdateKeyValue(account.name, SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI,
|
||||
arbitraryDataProvider.storeOrUpdateKeyValue(mAccount.name, SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI,
|
||||
String.valueOf(pUploadOnWifiCheckbox.isChecked()));
|
||||
|
||||
return true;
|
||||
|
@ -800,8 +838,6 @@ public class Preferences extends PreferenceActivity
|
|||
}
|
||||
|
||||
private void launchDavDroidLogin() {
|
||||
Account account = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
|
||||
|
||||
Intent davDroidLoginIntent = new Intent();
|
||||
davDroidLoginIntent.setClassName("at.bitfire.davdroid", "at.bitfire.davdroid.ui.setup.LoginActivity");
|
||||
if (getPackageManager().resolveActivity(davDroidLoginIntent, 0) != null) {
|
||||
|
@ -809,7 +845,7 @@ public class Preferences extends PreferenceActivity
|
|||
if (mUri != null) {
|
||||
davDroidLoginIntent.putExtra("url", mUri.toString() + DAV_PATH);
|
||||
}
|
||||
davDroidLoginIntent.putExtra("username", AccountUtils.getAccountUsername(account.name));
|
||||
davDroidLoginIntent.putExtra("username", AccountUtils.getAccountUsername(mAccount.name));
|
||||
//loginIntent.putExtra("password", "...");
|
||||
startActivityForResult(davDroidLoginIntent, ACTION_REQUEST_CODE_DAVDROID_SETUP);
|
||||
} else {
|
||||
|
@ -835,8 +871,7 @@ public class Preferences extends PreferenceActivity
|
|||
Thread t = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
Account account = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
|
||||
OwnCloudAccount ocAccount = new OwnCloudAccount(account, MainApp.getAppContext());
|
||||
OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, MainApp.getAppContext());
|
||||
mUri = OwnCloudClientManagerFactory.getDefaultSingleton().
|
||||
getClientFor(ocAccount, getApplicationContext()).getBaseUri();
|
||||
} catch (Throwable t) {
|
||||
|
@ -888,7 +923,7 @@ public class Preferences extends PreferenceActivity
|
|||
} else if (requestCode == ACTION_CONFIRM_DEVICE_CREDENTIALS && resultCode == RESULT_OK &&
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
||||
data.getIntExtra(RequestCredentialsActivity.KEY_CHECK_RESULT,
|
||||
RequestCredentialsActivity.KEY_CHECK_RESULT_FALSE) ==
|
||||
RequestCredentialsActivity.KEY_CHECK_RESULT_FALSE) ==
|
||||
RequestCredentialsActivity.KEY_CHECK_RESULT_TRUE) {
|
||||
mLock.setValue(LOCK_NONE);
|
||||
mLock.setSummary(mLock.getEntry());
|
||||
|
@ -896,6 +931,22 @@ public class Preferences extends PreferenceActivity
|
|||
if (!pendingLock.equals(LOCK_NONE)) {
|
||||
enableLock(pendingLock);
|
||||
}
|
||||
} else if (requestCode == PassCodeManager.PASSCODE_ACTIVITY && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
||||
data.getIntExtra(RequestCredentialsActivity.KEY_CHECK_RESULT,
|
||||
RequestCredentialsActivity.KEY_CHECK_RESULT_FALSE) ==
|
||||
RequestCredentialsActivity.KEY_CHECK_RESULT_TRUE) {
|
||||
|
||||
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
|
||||
String mnemonic = arbitraryDataProvider.getValue(mAccount.name, EncryptionUtils.MNEMONIC);
|
||||
|
||||
int accentColor = ThemeUtils.primaryAccentColor(this);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.FallbackTheming_Dialog);
|
||||
builder.setTitle(ThemeUtils.getColoredTitle(getString(R.string.prefs_e2e_mnemonic), accentColor));
|
||||
builder.setMessage(mnemonic);
|
||||
builder.setPositiveButton(ThemeUtils.getColoredTitle(getString(R.string.common_ok), accentColor),
|
||||
(dialog, which) -> dialog.dismiss());
|
||||
builder.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -185,9 +185,10 @@ public class SetupEncryptionDialogFragment extends DialogFragment {
|
|||
|
||||
try {
|
||||
String privateKey = task.get();
|
||||
String mnemonic = passwordField.getText().toString().replaceAll("\\s", "")
|
||||
.toLowerCase(Locale.ROOT);
|
||||
String decryptedPrivateKey = EncryptionUtils.decryptPrivateKey(privateKey,
|
||||
passwordField.getText().toString().replaceAll("\\s", "")
|
||||
.toLowerCase(Locale.ROOT));
|
||||
mnemonic);
|
||||
|
||||
arbitraryDataProvider.storeOrUpdateKeyValue(account.name,
|
||||
EncryptionUtils.PRIVATE_KEY, decryptedPrivateKey);
|
||||
|
@ -195,6 +196,9 @@ public class SetupEncryptionDialogFragment extends DialogFragment {
|
|||
dialog.dismiss();
|
||||
Log_OC.d(TAG, "Private key successfully decrypted and stored");
|
||||
|
||||
arbitraryDataProvider.storeOrUpdateKeyValue(account.name, EncryptionUtils.MNEMONIC,
|
||||
mnemonic);
|
||||
|
||||
Intent intentExisting = new Intent();
|
||||
intentExisting.putExtra(SUCCESS, true);
|
||||
intentExisting.putExtra(ARG_POSITION, getArguments().getInt(ARG_POSITION));
|
||||
|
@ -301,14 +305,7 @@ public class SetupEncryptionDialogFragment extends DialogFragment {
|
|||
|
||||
textView.setText(R.string.end_to_end_encryption_keywords_description);
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
for (String string : keyWords) {
|
||||
stringBuilder.append(string).append(" ");
|
||||
}
|
||||
String keys = stringBuilder.toString();
|
||||
|
||||
passphraseTextView.setText(keys);
|
||||
passphraseTextView.setText(generateMnemonicString(true));
|
||||
|
||||
passphraseTextView.setVisibility(View.VISIBLE);
|
||||
positiveButton.setText(R.string.end_to_end_encryption_confirm_button);
|
||||
|
@ -379,15 +376,10 @@ public class SetupEncryptionDialogFragment extends DialogFragment {
|
|||
return "";
|
||||
}
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (String string : keyWords) {
|
||||
stringBuilder.append(string);
|
||||
}
|
||||
String keyPhrase = stringBuilder.toString();
|
||||
|
||||
String privateKeyString = EncryptionUtils.encodeBytesToBase64String(privateKey.getEncoded());
|
||||
String privatePemKeyString = EncryptionUtils.privateKeyToPEM(privateKey);
|
||||
String encryptedPrivateKey = EncryptionUtils.encryptPrivateKey(privatePemKeyString, keyPhrase);
|
||||
String encryptedPrivateKey = EncryptionUtils.encryptPrivateKey(privatePemKeyString,
|
||||
generateMnemonicString(false));
|
||||
|
||||
// upload encryptedPrivateKey
|
||||
StorePrivateKeyOperation storePrivateKeyOperation = new StorePrivateKeyOperation(encryptedPrivateKey);
|
||||
|
@ -400,6 +392,8 @@ public class SetupEncryptionDialogFragment extends DialogFragment {
|
|||
arbitraryDataProvider.storeOrUpdateKeyValue(account.name, EncryptionUtils.PRIVATE_KEY,
|
||||
privateKeyString);
|
||||
arbitraryDataProvider.storeOrUpdateKeyValue(account.name, EncryptionUtils.PUBLIC_KEY, publicKey);
|
||||
arbitraryDataProvider.storeOrUpdateKeyValue(account.name, EncryptionUtils.MNEMONIC,
|
||||
generateMnemonicString(true));
|
||||
|
||||
keyResult = KEY_CREATED;
|
||||
return (String) storePrivateKeyResult.getData().get(0);
|
||||
|
@ -438,4 +432,17 @@ public class SetupEncryptionDialogFragment extends DialogFragment {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String generateMnemonicString(boolean withWhitespace) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
for (String string : keyWords) {
|
||||
stringBuilder.append(string);
|
||||
if (withWhitespace) {
|
||||
stringBuilder.append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,7 @@ public class EncryptionUtils {
|
|||
|
||||
public static final String PUBLIC_KEY = "PUBLIC_KEY";
|
||||
public static final String PRIVATE_KEY = "PRIVATE_KEY";
|
||||
public static final String MNEMONIC = "MNEMONIC";
|
||||
public static final int ivLength = 16;
|
||||
public static final int saltLength = 40;
|
||||
|
||||
|
|
|
@ -796,7 +796,9 @@
|
|||
<string name="sharee_add_failed">Adding sharee failed</string>
|
||||
<string name="unsharing_failed">Unsharing failed</string>
|
||||
<string name="updating_share_failed">Updating share failed</string>
|
||||
<string name="whats_new_device_credentials_title">Use Android device protection</string>
|
||||
<string name="prefs_e2e_mnemonic">E2E mnemonic</string>
|
||||
<string name="prefs_e2e_no_device_credentials">To show mnemonic please enable device credentials.</string>
|
||||
<string name="whats_new_device_credentials_title">Use Android\'s device internal protection</string>
|
||||
<string name="whats_new_device_credentials_content">Use anything like a pattern, password, pin or your fingerprint to keep your data safe.</string>
|
||||
<string name="restore_button_description">Restore deleted file</string>
|
||||
<string name="restore">Restore file</string>
|
||||
|
|
|
@ -45,6 +45,15 @@
|
|||
<item name="colorAccent">#757575</item>
|
||||
</style>
|
||||
|
||||
<style name="FallbackTheming.Dialog" parent="Theme.AppCompat.Light.Dialog.Alert">
|
||||
<item name="colorPrimary">#424242</item>
|
||||
<item name="colorPrimaryDark">#212121</item>
|
||||
<item name="colorAccent">#757575</item>
|
||||
<item name="windowNoTitle">false</item>
|
||||
<item name="buttonBarButtonStyle">@style/Theme.ownCloud.Dialog.ButtonBar.Button</item>
|
||||
<item name="buttonBarStyle">@style/Theme.ownCloud.Dialog.ButtonBar</item>
|
||||
</style>
|
||||
|
||||
<!-- seperate action bar style for activities without an action bar -->
|
||||
<style name="Theme.ownCloud.Toolbar" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="windowNoTitle">true</item>
|
||||
|
|
|
@ -60,6 +60,10 @@
|
|||
android:title="@string/actionbar_contacts"
|
||||
android:key="contacts"
|
||||
android:summary="@string/prefs_daily_contacts_sync_summary"/>
|
||||
<Preference
|
||||
android:title="@string/prefs_e2e_mnemonic"
|
||||
android:key="mnemonic"
|
||||
android:summary="Displays your E2E 12 words passphrase" />
|
||||
<Preference android:title="@string/prefs_help" android:key="help" />
|
||||
<Preference android:title="@string/prefs_recommend" android:key="recommend" />
|
||||
<Preference android:title="@string/prefs_feedback" android:key="feedback" />
|
||||
|
|
Loading…
Reference in a new issue