diff --git a/CHANGELOG b/CHANGELOG index 4c32467fb..3358b1cbe 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ KeepassDX (2.5.0.0beta12) * New adaptive launcher icon * Added a setting to disable the open button when no password is identified * Added a setting to disable the education screens + * Added a setting to disable the copy of protected custom fields * Fix the fingerprint recognition (WARNING : The keystore is reinit, you must delete the old keys) * Fix small bugs diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.java b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.java index e49fb8806..ef5da57ed 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.java +++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.java @@ -152,12 +152,28 @@ public class EntryActivity extends LockingHideActivity { // Start to manage field reference to copy a value from ref mEntry.startToManageFieldReferences(App.getDB().getPwDatabase()); + boolean containsUsernameToCopy = + mEntry.getUsername().length() > 0; + boolean containsPasswordToCopy = + (mEntry.getPassword().length() > 0 + && PreferencesUtil.allowCopyPasswordAndProtectedFields(this)); + boolean containsExtraFieldToCopy = + (mEntry.allowExtraFields() + && ((mEntry.containsCustomFields() + && mEntry.containsCustomFieldsNotProtected()) + || (mEntry.containsCustomFields() + && mEntry.containsCustomFieldsProtected() + && PreferencesUtil.allowCopyPasswordAndProtectedFields(this)) + ) + ); + // If notifications enabled in settings // Don't if application timeout if (firstLaunchOfActivity && !App.isShutdown() && isClipboardNotificationsEnable(getApplicationContext())) { - if (mEntry.getUsername().length() > 0 - || (mEntry.getPassword().length() > 0 && PreferencesUtil.allowCopyPassword(this)) - || mEntry.containsCustomFields()) { + if (containsUsernameToCopy + || containsPasswordToCopy + || containsExtraFieldToCopy + ) { // username already copied, waiting for user's action before copy password. Intent intent = new Intent(this, NotificationCopyingService.class); intent.setAction(NotificationCopyingService.ACTION_NEW_NOTIFICATION); @@ -166,35 +182,37 @@ public class EntryActivity extends LockingHideActivity { // Construct notification fields ArrayList notificationFields = new ArrayList<>(); // Add username if exists to notifications - if (mEntry.getUsername().length() > 0) + if (containsUsernameToCopy) notificationFields.add( new NotificationField( NotificationField.NotificationFieldId.USERNAME, mEntry.getUsername(), getResources())); // Add password to notifications - if (PreferencesUtil.allowCopyPassword(this)) { - if (mEntry.getPassword().length() > 0) - notificationFields.add( - new NotificationField( - NotificationField.NotificationFieldId.PASSWORD, - mEntry.getPassword(), - getResources())); + if (containsPasswordToCopy) { + notificationFields.add( + new NotificationField( + NotificationField.NotificationFieldId.PASSWORD, + mEntry.getPassword(), + getResources())); } // Add extra fields - if (mEntry.allowExtraFields()) { + if (containsExtraFieldToCopy) { try { mEntry.getFields().doActionToAllCustomProtectedField(new ExtraFields.ActionProtected() { private int anonymousFieldNumber = 0; @Override public void doAction(String key, ProtectedString value) { - notificationFields.add( - new NotificationField( - NotificationField.NotificationFieldId.getAnonymousFieldId()[anonymousFieldNumber], - value.toString(), - key, - getResources())); - anonymousFieldNumber++; + //If value is not protected or allowed + if (!value.isProtected() || PreferencesUtil.allowCopyPasswordAndProtectedFields(EntryActivity.this)) { + notificationFields.add( + new NotificationField( + NotificationField.NotificationFieldId.getAnonymousFieldId()[anonymousFieldNumber], + value.toString(), + key, + getResources())); + anonymousFieldNumber++; + } } }); } catch (ArrayIndexOutOfBoundsException e) { @@ -313,7 +331,7 @@ public class EntryActivity extends LockingHideActivity { ); entryContentsView.assignPassword(mEntry.getPassword()); - if (PreferencesUtil.allowCopyPassword(this)) { + if (PreferencesUtil.allowCopyPasswordAndProtectedFields(this)) { entryContentsView.assignPasswordCopyListener(view -> clipboardHelper.timeoutCopyToClipboard(mEntry.getPassword(), getString(R.string.copy_field, getString(R.string.entry_password))) @@ -329,14 +347,15 @@ public class EntryActivity extends LockingHideActivity { if (mEntry.allowExtraFields()) { entryContentsView.clearExtraFields(); - mEntry.getFields().doActionToAllCustomProtectedField((label, value) -> - - entryContentsView.addExtraField(label, value, view -> + mEntry.getFields().doActionToAllCustomProtectedField((label, value) -> { + boolean showAction = (!value.isProtected() || PreferencesUtil.allowCopyPasswordAndProtectedFields(EntryActivity.this)); + entryContentsView.addExtraField(label, value, showAction, view -> clipboardHelper.timeoutCopyToClipboard( value.toString(), getString(R.string.copy_field, label) ) - )); + ); + }); } // Assign dates diff --git a/app/src/main/java/com/kunzisoft/keepass/database/ExtraFields.java b/app/src/main/java/com/kunzisoft/keepass/database/ExtraFields.java index 93f5bb993..40ec63fa3 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/ExtraFields.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/ExtraFields.java @@ -44,6 +44,22 @@ public class ExtraFields implements Serializable, Cloneable { return !getCustomProtectedFields().keySet().isEmpty(); } + public boolean containsCustomFieldsProtected() { + for (Map.Entry field : getCustomProtectedFields().entrySet()) { + if (field.getValue().isProtected()) + return true; + } + return false; + } + + public boolean containsCustomFieldsNotProtected() { + for (Map.Entry field : getCustomProtectedFields().entrySet()) { + if (!field.getValue().isProtected()) + return true; + } + return false; + } + public String getProtectedStringValue(String key) { ProtectedString value = fields.get(key); if ( value == null ) return ""; diff --git a/app/src/main/java/com/kunzisoft/keepass/database/PwEntry.java b/app/src/main/java/com/kunzisoft/keepass/database/PwEntry.java index ede7b0da1..f3b015f5b 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/PwEntry.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/PwEntry.java @@ -117,6 +117,22 @@ public abstract class PwEntry extends PwNode { return getFields().containsCustomFields(); } + /** + * If entry contains extra fields that are protected + * @return true if there is extra fields protected + */ + public boolean containsCustomFieldsProtected() { + return getFields().containsCustomFieldsProtected(); + } + + /** + * If entry contains extra fields that are not protected + * @return true if there is extra fields not protected + */ + public boolean containsCustomFieldsNotProtected() { + return getFields().containsCustomFieldsNotProtected(); + } + /** * Add an extra field to the list (standard or custom) * @param label Label of field, must be unique diff --git a/app/src/main/java/com/kunzisoft/keepass/dialogs/StorageAccessFrameworkDialog.java b/app/src/main/java/com/kunzisoft/keepass/dialogs/StorageAccessFrameworkDialog.java deleted file mode 100644 index 34fd68a89..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/dialogs/StorageAccessFrameworkDialog.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft. - * - * This file is part of KeePass DX. - * - * KeePass DX is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * KeePass DX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with KeePass DX. If not, see . - * - */ -package com.kunzisoft.keepass.dialogs; - -import android.content.Context; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.app.AlertDialog; - -import com.kunzisoft.keepass.R; - -public class StorageAccessFrameworkDialog extends AlertDialog { - - public StorageAccessFrameworkDialog(@NonNull Context context) { - super(context); - } - - public StorageAccessFrameworkDialog(@NonNull Context context, int themeResId) { - super(context, themeResId); - } - - public StorageAccessFrameworkDialog(@NonNull Context context, boolean cancelable, @Nullable OnCancelListener cancelListener) { - super(context, cancelable, cancelListener); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - Context ctx = getContext(); - setMessage(ctx.getString(R.string.warning_disabling_storage_access_framework)); - - super.onCreate(savedInstanceState); - } -} diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/NestedSettingsFragment.java b/app/src/main/java/com/kunzisoft/keepass/settings/NestedSettingsFragment.java index 96d69952c..0f7595818 100644 --- a/app/src/main/java/com/kunzisoft/keepass/settings/NestedSettingsFragment.java +++ b/app/src/main/java/com/kunzisoft/keepass/settings/NestedSettingsFragment.java @@ -33,7 +33,6 @@ import android.support.annotation.RequiresApi; import android.support.v14.preference.SwitchPreference; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentManager; -import android.support.v4.hardware.fingerprint.FingerprintManagerCompat; import android.support.v7.app.AlertDialog; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceCategory; @@ -47,7 +46,6 @@ import com.kunzisoft.keepass.R; import com.kunzisoft.keepass.app.App; import com.kunzisoft.keepass.database.Database; import com.kunzisoft.keepass.dialogs.ProFeatureDialogFragment; -import com.kunzisoft.keepass.dialogs.StorageAccessFrameworkDialog; import com.kunzisoft.keepass.dialogs.UnavailableFeatureDialogFragment; import com.kunzisoft.keepass.dialogs.UnderDevelopmentFeatureDialogFragment; import com.kunzisoft.keepass.fingerprint.FingerPrintHelper; @@ -117,6 +115,8 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat case APPLICATION: setPreferencesFromResource(R.xml.application_preferences, rootKey); + allowCopyPassword(); + Preference keyFile = findPreference(getString(R.string.keyfile_key)); keyFile.setOnPreferenceChangeListener((preference, newValue) -> { Boolean value = (Boolean) newValue; @@ -142,17 +142,18 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat storageAccessFramework.setOnPreferenceChangeListener((preference, newValue) -> { Boolean value = (Boolean) newValue; if (!value && getContext() != null) { - StorageAccessFrameworkDialog safDialog = new StorageAccessFrameworkDialog(getContext()); - safDialog.setButton(AlertDialog.BUTTON1, getText(android.R.string.ok), + AlertDialog alertDialog = new AlertDialog.Builder(getContext()) + .setMessage(getString(R.string.warning_disabling_storage_access_framework)).create(); + alertDialog.setButton(AlertDialog.BUTTON1, getText(android.R.string.ok), (dialog, which) -> { dialog.dismiss(); }); - safDialog.setButton(AlertDialog.BUTTON2, getText(android.R.string.cancel), + alertDialog.setButton(AlertDialog.BUTTON2, getText(android.R.string.cancel), (dialog, which) -> { storageAccessFramework.setChecked(true); dialog.dismiss(); }); - safDialog.show(); + alertDialog.show(); } return true; }); @@ -297,6 +298,9 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat return false; }); + // Present in two places + allowCopyPassword(); + break; case DATABASE: @@ -427,6 +431,28 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat } } + private void allowCopyPassword() { + SwitchPreference copyPasswordPreference = (SwitchPreference) findPreference(getString(R.string.allow_copy_password_key)); + copyPasswordPreference.setOnPreferenceChangeListener((preference, newValue) -> { + if ((Boolean) newValue && getContext() != null) { + String message = getString(R.string.allow_copy_password_warning) + + "\n\n" + + getString(R.string.clipboard_warning); + AlertDialog warningDialog = new AlertDialog.Builder(getContext()) + .setMessage(message).create(); + warningDialog.setButton(AlertDialog.BUTTON1, getText(android.R.string.ok), + (dialog, which) -> dialog.dismiss()); + warningDialog.setButton(AlertDialog.BUTTON2, getText(android.R.string.cancel), + (dialog, which) -> { + copyPasswordPreference.setChecked(false); + dialog.dismiss(); + }); + warningDialog.show(); + } + return true; + }); + } + private void preferenceInDevelopment(Preference preferenceInDev) { preferenceInDev.setOnPreferenceClickListener(preference -> { FragmentManager fragmentManager = getFragmentManager(); diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.java b/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.java index 4aa144494..932b2d1f8 100644 --- a/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.java +++ b/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.java @@ -139,7 +139,7 @@ public class PreferencesUtil { ctx.getResources().getBoolean(R.bool.auto_open_file_uri_default)); } - public static boolean allowCopyPassword(Context ctx) { + public static boolean allowCopyPasswordAndProtectedFields(Context ctx) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); return prefs.getBoolean(ctx.getString(R.string.allow_copy_password_key), ctx.getResources().getBoolean(R.bool.allow_copy_password_default)); diff --git a/app/src/main/java/com/kunzisoft/keepass/timeout/ClipboardHelper.java b/app/src/main/java/com/kunzisoft/keepass/timeout/ClipboardHelper.java index b9f842965..600bec421 100644 --- a/app/src/main/java/com/kunzisoft/keepass/timeout/ClipboardHelper.java +++ b/app/src/main/java/com/kunzisoft/keepass/timeout/ClipboardHelper.java @@ -98,7 +98,7 @@ public class ClipboardHelper { public void copyToClipboard(String label, String value) throws SamsungClipboardException { try { clipboardManager.setPrimaryClip(ClipData.newPlainText(label, value)); - } catch (NullPointerException e) { + } catch (Exception e) { throw new SamsungClipboardException(e); } } diff --git a/app/src/main/java/com/kunzisoft/keepass/view/EntryContentsView.java b/app/src/main/java/com/kunzisoft/keepass/view/EntryContentsView.java index a2854dab7..50824a610 100644 --- a/app/src/main/java/com/kunzisoft/keepass/view/EntryContentsView.java +++ b/app/src/main/java/com/kunzisoft/keepass/view/EntryContentsView.java @@ -193,12 +193,12 @@ public class EntryContentsView extends LinearLayout { } } - public void addExtraField(String title, ProtectedString value, OnClickListener onActionClickListener) { + public void addExtraField(String title, ProtectedString value, boolean showAction, OnClickListener onActionClickListener) { EntryCustomField entryCustomField; if (value.isProtected()) - entryCustomField = new EntryCustomFieldProtected(getContext(), null, title, value, onActionClickListener); + entryCustomField = new EntryCustomFieldProtected(getContext(), null, title, value, showAction, onActionClickListener); else - entryCustomField = new EntryCustomField(getContext(), null, title, value, onActionClickListener); + entryCustomField = new EntryCustomField(getContext(), null, title, value, showAction, onActionClickListener); entryCustomField.applyFontVisibility(fontInVisibility); extrasView.addView(entryCustomField); } diff --git a/app/src/main/java/com/kunzisoft/keepass/view/EntryCustomField.java b/app/src/main/java/com/kunzisoft/keepass/view/EntryCustomField.java index 56733d4d1..c0fb6ce44 100644 --- a/app/src/main/java/com/kunzisoft/keepass/view/EntryCustomField.java +++ b/app/src/main/java/com/kunzisoft/keepass/view/EntryCustomField.java @@ -45,10 +45,10 @@ public class EntryCustomField extends LinearLayout { } public EntryCustomField(Context context, AttributeSet attrs, String title, ProtectedString value) { - this(context, attrs, title, value, null); + this(context, attrs, title, value, false, null); } - public EntryCustomField(Context context, AttributeSet attrs, String label, ProtectedString value, OnClickListener onClickActionListener) { + public EntryCustomField(Context context, AttributeSet attrs, String label, ProtectedString value, boolean showAction, OnClickListener onClickActionListener) { super(context, attrs); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -61,7 +61,12 @@ public class EntryCustomField extends LinearLayout { setLabel(label); setValue(value); - setAction(onClickActionListener); + + if (!showAction) { + actionImageView.setVisibility(INVISIBLE); + } else { + setAction(onClickActionListener); + } } public void applyFontVisibility(boolean fontInVisibility) { diff --git a/app/src/main/java/com/kunzisoft/keepass/view/EntryCustomFieldProtected.java b/app/src/main/java/com/kunzisoft/keepass/view/EntryCustomFieldProtected.java index b5ae29ccb..117b100ef 100644 --- a/app/src/main/java/com/kunzisoft/keepass/view/EntryCustomFieldProtected.java +++ b/app/src/main/java/com/kunzisoft/keepass/view/EntryCustomFieldProtected.java @@ -39,8 +39,8 @@ public class EntryCustomFieldProtected extends EntryCustomField{ super(context, attrs, title, value); } - public EntryCustomFieldProtected(Context context, AttributeSet attrs, String label, ProtectedString value, OnClickListener onClickActionListener) { - super(context, attrs, label, value, onClickActionListener); + public EntryCustomFieldProtected(Context context, AttributeSet attrs, String label, ProtectedString value, boolean showAction, OnClickListener onClickActionListener) { + super(context, attrs, label, value, showAction, onClickActionListener); } public void setValue(ProtectedString value) { diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index ed33c9345..e0ec03128 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -212,7 +212,8 @@ Définir les caractères par défaut du générateur de mot de passe Notifications Notifications du presse-papiers - Activer les notifications du presse-papiers pour copier le nom d\'utilisateur et le mot de passe + Activer les notifications du presse-papiers pour copier les champs d\'entrées + Certains appareils ne sont pas en mesure de supprimer automatiquement les éléments du presse-papiers. Si votre gestionnaire n\'autorise pas cette suppression, vous devrez supprimer manuellement l\'élément copié de l\'historique de votre presse-papiers. Verrouillage d\'écran Verrouiller la base de données quand l\'écran est éteint Comment configurer l\'empreinte digitale pour un déverrouillage rapide? @@ -249,7 +250,8 @@ Ouvrir le fichier sélectionné automatiquement Ouvrir automatiquement un fichier à partir de l\'écran de sélection après une sélection dans le navigateur de fichiers Copie de mot de passe - Autoriser la copie du mot de passe dans le presse-papiers. + Autoriser la copie du mot de passe et des champs protégés dans le presse-papiers. + ATTENTION : Le presse-papiers est partagé par toutes les applications. Si des données sensibles sont copiés, d\'autres logiciels peuvent les récupérer. ATTENTION : désactiver cette fonctionnalité peut engendrer une impossibilité d\'ouvrir ou sauvegarder les bases de données Lien du fichier Kdbx à ouvrir Nom de la base de données diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index a0c834538..8d7c325cf 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -118,7 +118,7 @@ true true true - true + false true false false diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9472ec115..74789a2a7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -215,7 +215,8 @@ Set the default password generator characters Notifications Clipboard Notifications - Enable clipboard notifications to copy username and password + Enable clipboard notifications to copy entry fields + Some devices are not able to automatically delete clips from the clipboard. If your manager does not allow this deletion, you will have to manually delete the copied item from your clipboard history. Lock Screen lock Lock the database when the screen is off @@ -253,7 +254,8 @@ Auto open selected file Automatically open a file from the selection screen after a selection in the file browser Copy of password - Allow the copy of the password to the clipboard. + Allow the copy of the password and protected fields to the clipboard. + WARNING : The clipboard is shared by all applications. If sensitive data is copied, other software may recover it. WARNING : disabling this feature may result in an inability to open or save the databases Link of the Kdbx file to open Database name diff --git a/app/src/main/res/xml/form_filling_preferences.xml b/app/src/main/res/xml/form_filling_preferences.xml index 38f8d8322..8c6c6f72e 100644 --- a/app/src/main/res/xml/form_filling_preferences.xml +++ b/app/src/main/res/xml/form_filling_preferences.xml @@ -45,6 +45,11 @@ android:title="@string/clipboard_notifications_title" android:defaultValue="@bool/clipboard_notifications_default" android:summary="@string/clipboard_notifications_summary" /> + \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/12.txt b/fastlane/metadata/android/en-US/changelogs/12.txt index 7baa23bd0..6637169fd 100644 --- a/fastlane/metadata/android/en-US/changelogs/12.txt +++ b/fastlane/metadata/android/en-US/changelogs/12.txt @@ -3,6 +3,5 @@ * New navigation in a single screen / new animations between activities * New icons for the material pack * New adaptive launcher icon - * Added a setting to disable the open button when no password is identified - * Added a setting to disable the education screens + * Added a setting to disable the open button when no password is identified / the education screens / the copy of protected custom fields * Fix the fingerprint recognition (WARNING : The keystore is reinit, you must delete the old keys) \ No newline at end of file diff --git a/fastlane/metadata/android/fr-FR/changelogs/12.txt b/fastlane/metadata/android/fr-FR/changelogs/12.txt index 8d86bac68..5b0674d50 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/12.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/12.txt @@ -3,6 +3,5 @@ * Nouvelle navigation dans un seul écran / nouvelles animations entre activités * Nouveaux icones pour le pack material * Nouvel icone de lancement adaptatif - * Ajout d'un paramètre pour désactiver le bouton d'ouverture quand aucun mot de passe n'est identifié - * Ajout d'un paramètre pour désactiver les écrans d'éducation + * Ajout d'un paramètre pour désactiver le bouton d'ouverture quand aucun mot de passe n'est identifié / les écrans d'éducation / la copie des champs customisés protégés * Correction de la reconnaissance des empreintes digitales (ATTENTION: le keystore est réinitialisé, vous devez supprimer les anciennes clés) \ No newline at end of file