Browse Source

Credit page, warn user when using unencrypted passwords

isundil 4 years ago
parent
commit
2102f06721

+ 1 - 1
.idea/misc.xml

@@ -29,7 +29,7 @@
       </value>
     </option>
   </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/build/classes" />
   </component>
   <component name="ProjectType">

+ 1 - 0
.idea/runConfigurations.xml

@@ -3,6 +3,7 @@
   <component name="RunConfigurationProducerService">
     <option name="ignoredProducers">
       <set>
+        <option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
         <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
         <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
         <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />

+ 2 - 2
app/build.gradle

@@ -14,8 +14,8 @@ android {
         applicationId "info.knacki.pass"
         minSdkVersion 15
         targetSdkVersion 29
-        versionCode 2
-        versionName "1.0.2"
+        versionCode 4
+        versionName "1.0.4"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
         vectorDrawables.useSupportLibrary = true
         signingConfig signingConfigs.release

+ 18 - 3
app/src/main/java/info/knacki/pass/io/FileInterfaceFactory.java

@@ -20,9 +20,9 @@ public class FileInterfaceFactory {
     private static final ArrayDeque<EncryptionMethodItem> fEncryptionMethods = new ArrayDeque<>();
 
     static {
-        fEncryptionMethods.add(new EncryptionMethodItem((ctx, passwordGetter, file) -> new RawFileInterface(ctx.getResources(), file), SettingsManager.EncryptionType.TYPE_RAW,".raw", R.string.pref_enc_type_title_none));
-        fEncryptionMethods.add(new EncryptionMethodItem(GPGFileInterface::new, SettingsManager.EncryptionType.TYPE_GPG,".gpg", R.string.pref_enc_type_title_gpg));
-        fEncryptionMethods.add(new EncryptionMethodItem(PasswordFileInterface::new, SettingsManager.EncryptionType.TYPE_PASSWORD, PasswordFileInterface.PASSWORD_SUFFIX, R.string.pref_enc_type_title_password));
+        fEncryptionMethods.add(new EncryptionMethodItem(new RawFileInterface.Creator(), SettingsManager.EncryptionType.TYPE_RAW,".raw", R.string.pref_enc_type_title_none));
+        fEncryptionMethods.add(new EncryptionMethodItem(new GPGFileInterface.Creator(), SettingsManager.EncryptionType.TYPE_GPG,".gpg", R.string.pref_enc_type_title_gpg));
+        fEncryptionMethods.add(new EncryptionMethodItem(new PasswordFileInterface.Creator(), SettingsManager.EncryptionType.TYPE_PASSWORD, PasswordFileInterface.PASSWORD_SUFFIX, R.string.pref_enc_type_title_password));
     }
 
     public interface OnPasswordEnteredListener extends OnErrorListener {
@@ -71,6 +71,17 @@ public class FileInterfaceFactory {
         throw new NoSuchMethodError();
     }
 
+    protected static EncryptionMethodItem GetEncryptionMethodForName(String fileName) {
+        if (PathUtils.IsHidden(fileName)) {
+            fileName = PathUtils.UnHiddenPath(fileName);
+        }
+        for (EncryptionMethodItem i: fEncryptionMethods)
+            if (fileName.endsWith(i.fFileSuffix))
+                return i;
+        log.severe("Unknown Interface for file type " +fileName);
+        throw new NoSuchMethodError();
+    }
+
     public static SettingsManager.EncryptionType GetEncryptionType(File f) {
         return GetEncryptionMethod(f).fEncryptionType;
     }
@@ -79,6 +90,10 @@ public class FileInterfaceFactory {
         return GetEncryptionMethod(f).fFactory.Create(ctx, passInput, f);
     }
 
+    public static IFileInterface GetReadFileInterface(Context ctx, PasswordGetter passInput, String filename, byte[] in) {
+        return GetEncryptionMethodForName(filename).fFactory.Create(ctx, passInput, in);
+    }
+
     public static String GetExtension(SettingsManager.EncryptionType type) {
         for (EncryptionMethodItem i: fEncryptionMethods)
             if (i.fEncryptionType.equals(type))

+ 9 - 4
app/src/main/java/info/knacki/pass/io/FileMigratoryUtils.java

@@ -6,6 +6,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.charset.Charset;
 import java.util.ArrayDeque;
 import java.util.logging.Logger;
 import java.util.zip.ZipEntry;
@@ -194,7 +195,7 @@ public class FileMigratoryUtils {
 
                         @Override
                         public void OnError(String msg, Throwable e) {
-                            onDone.OnError(msg, e);
+                            onDone.OnError("Write file (" +output.getName() +"): " +msg, e);
                         }
                     });
                 }
@@ -204,7 +205,7 @@ public class FileMigratoryUtils {
             }
         };
         final DoWrite _do = new DoWrite();
-        (new PasswordFileInterface(ctx, passwordGetter, in)).ReadFile(new OnResponseListener<String>() {
+        FileInterfaceFactory.GetReadFileInterface(ctx, passwordGetter, fileName, in).ReadFile(new OnResponseListener<String>() {
             @Override
             public void OnResponse(String result) {
                 File output = new File(PathUtils.GetPassDir(ctx), fileName);
@@ -232,13 +233,17 @@ public class FileMigratoryUtils {
 
             @Override
             public void OnError(String msg, Throwable e) {
-                onDone.OnError(msg, e);
+                onDone.OnError("Read File (" +fileName +"): " +msg, e);
             }
         });
     }
 
     public static void ImportAllPasswords(final Context ctx, InputStream in, FileInterfaceFactory.PasswordGetter _passwordGetter, OnResponseListener<Integer> onDone) {
-        final ZipInputStream stream = new ZipInputStream(in);
+        final ZipInputStream stream;
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N)
+            stream = new ZipInputStream(in, Charset.forName("UTF-8"));
+        else
+            stream = new ZipInputStream(in);
         final PasswordGetterWithCache passwordGetter = new PasswordGetterWithCache(_passwordGetter);
 
         final Runnable nextFile = new Runnable() {

+ 1 - 0
app/src/main/java/info/knacki/pass/io/IFileInterface.java

@@ -10,6 +10,7 @@ public interface IFileInterface {
 
     interface IFileInterfaceCreator {
         IFileInterface Create(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, File file);
+        IFileInterface Create(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, byte[] content);
     }
 
     class InvalidPasswordException extends Throwable {

+ 12 - 8
app/src/main/java/info/knacki/pass/io/PasswordFileInterface.java

@@ -70,20 +70,24 @@ class PasswordFileInterface implements IFileInterface {
         }
     }
 
-    PasswordFileInterface(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, File f) {
-        fFile = new FileOrContent(f);
+    private PasswordFileInterface(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, FileOrContent f) {
+        fFile = f;
         fPasswordGetter = passwordGetter;
         fPassword = SettingsManager.GetPassword(ctx).toCharArray();
         Resources r = ctx.getResources();
         fMethodName = r.getString(R.string.pref_enc_type_title_password);
     }
 
-    public PasswordFileInterface(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, byte[] encryptedContent) {
-        fPasswordGetter = passwordGetter;
-        fPassword = SettingsManager.GetPassword(ctx).toCharArray();
-        Resources r = ctx.getResources();
-        fMethodName = r.getString(R.string.pref_enc_type_title_password);
-        fFile = new FileOrContent(encryptedContent);
+    public static class Creator implements IFileInterfaceCreator {
+        @Override
+        public IFileInterface Create(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, File file) {
+            return new PasswordFileInterface(ctx, passwordGetter, new FileOrContent(file));
+        }
+
+        @Override
+        public IFileInterface Create(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, byte[] content) {
+            return new PasswordFileInterface(ctx, passwordGetter, new FileOrContent(content));
+        }
     }
 
     private static boolean TryDecryptStream(String pass, InputStream in, OnResponseListener<InputStream> onResponse) {

+ 27 - 2
app/src/main/java/info/knacki/pass/io/RawFileInterface.java

@@ -1,5 +1,6 @@
 package info.knacki.pass.io;
 
+import android.content.Context;
 import android.content.res.Resources;
 
 import java.io.File;
@@ -10,16 +11,40 @@ import info.knacki.gitdroid.callback.OnResponseListener;
 import info.knacki.pass.R;
 
 class RawFileInterface implements IFileInterface {
-    private static File fFile;
+    private final File fFile;
+    private final byte[] fFileContent;
     private final String fMethodName;
 
-    RawFileInterface(Resources r, File f) {
+    private RawFileInterface(Resources r, File f) {
         fFile = f;
+        fFileContent = null;
         fMethodName = r.getString(R.string.pref_enc_type_title_none);
     }
 
+    private RawFileInterface(Resources r, byte[] content) {
+        fFileContent = content;
+        fFile = null;
+        fMethodName = r.getString(R.string.pref_enc_type_title_none);
+    }
+
+    static class Creator implements IFileInterfaceCreator {
+        @Override
+        public IFileInterface Create(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, File file) {
+            return new RawFileInterface(ctx.getResources(), file);
+        }
+
+        @Override
+        public IFileInterface Create(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, byte[] content) {
+            return new RawFileInterface(ctx.getResources(), content);
+        }
+    }
+
     @Override
     public void ReadFile(OnResponseListener<String> resp) {
+        if (fFileContent != null) {
+            resp.OnResponse(new String(fFileContent));
+            return;
+        }
         try {
             resp.OnResponse(FileUtils.ReadAllFile(fFile));
         }

+ 33 - 4
app/src/main/java/info/knacki/pass/io/pgp/GPGFileInterface.java

@@ -16,25 +16,50 @@ import info.knacki.gitdroid.callback.OnResponseListener;
 
 public class GPGFileInterface implements IFileInterface {
     private final File fFile;
+    private final byte[] fFileContent;
     private final FileInterfaceFactory.PasswordGetter fPasswordGetter;
     private final Context fContext;
 
-    public GPGFileInterface(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, File f) {
+    private GPGFileInterface(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, File f) {
         fFile = f;
+        fFileContent = null;
         fPasswordGetter = passwordGetter;
         fContext = ctx;
     }
 
+    private GPGFileInterface(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, byte[] content) {
+        fFile = null;
+        fFileContent = content;
+        fPasswordGetter = passwordGetter;
+        fContext = ctx;
+    }
+
+    public static class Creator implements IFileInterfaceCreator {
+        @Override
+        public IFileInterface Create(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, File file) {
+            return new GPGFileInterface(ctx, passwordGetter, file);
+        }
+
+        @Override
+        public IFileInterface Create(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, byte[] content) {
+            return new GPGFileInterface(ctx, passwordGetter, content);
+        }
+    }
+
+    private long fileSize() {
+        return fFile == null ? fFileContent.length : fFile.length();
+    }
+
     @Override
     public void ReadFile(final OnResponseListener<String> resp) {
-        if (fFile.length() == 0) {
+        if (fileSize() == 0) {
             resp.OnResponse("");
             return;
         }
         try {
             if (!GPGStorageEngine.GetDefaultEngine(fContext).HasGPGKey())
                 throw new FileNotFoundException("GPG key not set");
-            GPGUtil.DecryptFile(fContext, fPasswordGetter, fFile, new OnResponseListener<byte[]>() {
+            OnResponseListener<byte[]> onResp = new OnResponseListener<byte[]>() {
                 @Override
                 public void OnResponse(byte[] result) {
                     resp.OnResponse(CharsetHelper.ByteArrayToString(result));
@@ -44,7 +69,11 @@ public class GPGFileInterface implements IFileInterface {
                 public void OnError(String msg, Throwable e) {
                     resp.OnError(msg, e);
                 }
-            });
+            };
+            if (fFile != null)
+                GPGUtil.DecryptFile(fContext, fPasswordGetter, fFile, onResp);
+            else
+                GPGUtil.DecryptFile(fContext, fPasswordGetter, fFileContent, onResp);
         } catch (Throwable e) {
             resp.OnError(e.getMessage(), e);
         }

+ 11 - 4
app/src/main/java/info/knacki/pass/io/pgp/GPGUtil.java

@@ -61,8 +61,8 @@ import java.util.NoSuchElementException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import info.knacki.pass.io.FileInterfaceFactory;
 import info.knacki.gitdroid.callback.OnResponseListener;
+import info.knacki.pass.io.FileInterfaceFactory;
 
 public class GPGUtil {
     private final static Logger log = Logger.getLogger(GPGUtil.class.getName());
@@ -209,8 +209,8 @@ public class GPGUtil {
         return PGPSecretKeyRing.copyWithNewPassword(secKeyring, keyDecryptor, newEncryptor);
     }
 
-    public static void DecryptFile(final Context ctx, final FileInterfaceFactory.PasswordGetter passwordGetter, final File file, final OnResponseListener<byte[]> resp) throws IOException {
-        PGPObjectFactory pgpF = new PGPObjectFactory(PGPUtil.getDecoderStream(new FileInputStream(file)), new JcaKeyFingerprintCalculator());
+    private static void DecryptFile(final Context ctx, final FileInterfaceFactory.PasswordGetter passwordGetter, final InputStream inputStream, final OnResponseListener<byte[]> resp) throws IOException {
+        PGPObjectFactory pgpF = new PGPObjectFactory(PGPUtil.getDecoderStream(inputStream), new JcaKeyFingerprintCalculator());
         Object o = pgpF.nextObject();
         final Iterator<?> it = ((o instanceof PGPEncryptedDataList) ? (PGPEncryptedDataList) o : (PGPEncryptedDataList) pgpF.nextObject()).getEncryptedDataObjects();
 
@@ -235,7 +235,14 @@ public class GPGUtil {
                             resp.OnError(msg, e);
                         }
                     });
-        }
+        }    }
+
+    public static void DecryptFile(final Context ctx, final FileInterfaceFactory.PasswordGetter passwordGetter, final byte[] fileContent, final OnResponseListener<byte[]> resp) throws IOException {
+        DecryptFile(ctx, passwordGetter, new ByteArrayInputStream(fileContent), resp);
+    }
+
+    public static void DecryptFile(final Context ctx, final FileInterfaceFactory.PasswordGetter passwordGetter, final File file, final OnResponseListener<byte[]> resp) throws IOException {
+        DecryptFile(ctx, passwordGetter, new FileInputStream(file), resp);
     }
 
     public static void CryptFile(final Context ctx, final OutputStream fileOutStream, final byte[] data, final OnResponseListener<Void> resp) {

+ 42 - 2
app/src/main/java/info/knacki/pass/settings/ui/SettingsActivity.java

@@ -17,14 +17,20 @@ import android.preference.PreferenceActivity;
 import android.preference.PreferenceFragment;
 import android.preference.SwitchPreference;
 import android.provider.Settings;
+import android.support.annotation.Nullable;
 import android.support.v4.app.ShareCompat;
 import android.support.v4.content.FileProvider;
 import android.support.v7.app.ActionBar;
+import android.support.v7.view.ContextThemeWrapper;
+import android.text.TextUtils;
 import android.util.SparseArray;
+import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
+import android.widget.LinearLayout;
 import android.widget.Toast;
 
 import java.io.ByteArrayInputStream;
@@ -138,7 +144,8 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
                 || EncryptionPreferenceFragment.class.getName().equals(fragmentName)
                 || VCSPreferenceFragment.class.getName().equals(fragmentName)
                 || GPGPreferenceFragment.class.getName().equals(fragmentName)
-                || PasswordPreferenceFragment.class.getName().equals(fragmentName);
+                || PasswordPreferenceFragment.class.getName().equals(fragmentName)
+                || CreditsFragment.class.getName().equals(fragmentName);
     }
 
     public static class GeneralPreferenceFragment extends PreferenceFragment {
@@ -666,7 +673,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
 
                     @Override
                     public void OnError(String msg, Throwable e) {
-                        Toast.makeText(getActivity(), getResources().getString(R.string.pass_import_ko), Toast.LENGTH_LONG).show();
+                        Toast.makeText(getActivity(), getResources().getString(R.string.pass_import_ko) +": " +msg, Toast.LENGTH_LONG).show();
                     }
                 });
             }
@@ -843,4 +850,37 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
             findPreference(getString(R.string.id_pwd_password)).setSummary(SettingsManager.HasPassword(getActivity()) ? R.string.pref_summary_pwd_password : R.string.pref_summary_pwd_new_password);
         }
     }
+
+    public static class CreditsFragment extends PreferenceFragment {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            setHasOptionsMenu(true);
+        }
+
+        private void AddCredit(Context ctx, LinearLayout container, int headerTextRes, int contentTextRes) {
+            TextView header = new TextView(new ContextThemeWrapper(ctx, R.style.CreditHeaderStyle));
+            header.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+            header.SetText(headerTextRes);
+            header.setPadding(0, 50, 0, 0);
+            container.addView(header);
+
+            TextView content = new TextView(new ContextThemeWrapper(ctx, R.style.CreditContentStyle));
+            content.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+            content.SetText("- " + TextUtils.join("\n- ", getResources().getStringArray(contentTextRes)));
+            container.addView(content);
+        }
+
+        @Override
+        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+            final View root = inflater.inflate(R.layout.activity_credits, container, false);
+            final LinearLayout creditContainer = root.findViewById(R.id.credit_text_container);
+            final Context ctx = getActivity();
+
+            AddCredit(ctx, creditContainer, R.string.credit_dev_header, R.array.credit_dev_text);
+            AddCredit(ctx, creditContainer, R.string.credit_images_header, R.array.credit_images_text);
+            AddCredit(ctx, creditContainer, R.string.credit_special_header, R.array.credit_special_text);
+            return root;
+        }
+    }
 }

+ 40 - 7
app/src/main/java/info/knacki/pass/ui/EditPasswordActivity.java

@@ -1,5 +1,6 @@
 package info.knacki.pass.ui;
 
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.v7.app.AppCompatActivity;
@@ -9,17 +10,20 @@ import android.text.Editable;
 import android.text.InputType;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.View;
+import android.widget.TextView;
 import android.widget.Toast;
 
 import java.io.File;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import info.knacki.gitdroid.callback.OnResponseListener;
 import info.knacki.pass.R;
 import info.knacki.pass.io.FileInterfaceFactory;
 import info.knacki.pass.io.IFileInterface;
-import info.knacki.gitdroid.callback.OnResponseListener;
 import info.knacki.pass.settings.SettingsManager;
+import info.knacki.pass.settings.ui.SettingsActivity;
 import info.knacki.pass.ui.passwordPicker.PasswordPickerFactory;
 
 public class EditPasswordActivity extends AppCompatActivity {
@@ -39,17 +43,30 @@ public class EditPasswordActivity extends AppCompatActivity {
         return super.onCreateOptionsMenu(menu);
     }
 
+    private void ShowFileInfo() {
+        Intent i = new Intent(this, EncryptionInformationActivity.class);
+        i.putExtra(EncryptionInformationActivity.FILE_PATH, fOutputFile.getAbsolutePath());
+        startActivity(i);
+    }
+
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         if (item.getItemId() == R.id.encryption_information) {
-            Intent i = new Intent(this, EncryptionInformationActivity.class);
-            i.putExtra(EncryptionInformationActivity.FILE_PATH, fOutputFile.getAbsolutePath());
-            startActivity(i);
+            ShowFileInfo();
             return true;
         }
         return super.onOptionsItemSelected(item);
     }
 
+    private String PrepareText(Editable t) {
+        if (t == null)
+            return "";
+        StringBuilder sb = new StringBuilder();
+        for (String i: t.toString().split("\r?\n"))
+            sb.append(i.trim()).append("\n");
+        return sb.toString();
+    }
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -61,14 +78,28 @@ public class EditPasswordActivity extends AppCompatActivity {
         }
         fOutputFile = new File(path);
         fTextEdit = findViewById(R.id.password_edit);
+        TextView rawFileWarning = findViewById(R.id.unencrypted_warning);
+        rawFileWarning.setVisibility(View.GONE);
+        if (SettingsManager.GetDefaultEncryptionType(getApplicationContext()).equals(SettingsManager.EncryptionType.TYPE_RAW)) {
+            rawFileWarning.setOnClickListener(v -> {
+                Context ctx = EditPasswordActivity.this.getApplicationContext();
+                Intent i = new Intent(ctx, SettingsActivity.class);
+                i.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, SettingsActivity.EncryptionPreferenceFragment.class.getName());
+                ctx.startActivity(i);
+            });
+        } else {
+            rawFileWarning.setText(R.string.password_not_encrypted);
+            rawFileWarning.setOnClickListener(v -> {
+                ShowFileInfo();
+            });
+        }
         ((AppCompatCheckBox) findViewById(R.id.showPasswordCheckbox)).setOnCheckedChangeListener((compoundButton, b) -> {
             final int cursorPos = fTextEdit.getSelectionEnd();
             fTextEdit.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | (compoundButton.isChecked() ? InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD : InputType.TYPE_TEXT_VARIATION_PASSWORD));
             fTextEdit.setSelection(cursorPos);
         });
         findViewById(R.id.saveButton).setOnClickListener(view -> {
-            final Editable text = fTextEdit.getText();
-            final String textStr = text == null ? "" : text.toString();
+            final String textStr = PrepareText(fTextEdit.getText());
 
             try {
                 FileInterfaceFactory.GetFileInterface(EditPasswordActivity.this, PasswordPickerFactory.GetPasswordPicker(EditPasswordActivity.this), fOutputFile).WriteFile(textStr, new OnResponseListener<Void>() {
@@ -100,12 +131,14 @@ public class EditPasswordActivity extends AppCompatActivity {
 
     protected void populateContent(final boolean requestFocus) {
         fTextEdit.setEnabled(false);
+        if (FileInterfaceFactory.GetEncryptionType(fOutputFile).equals(SettingsManager.EncryptionType.TYPE_RAW))
+            findViewById(R.id.unencrypted_warning).setVisibility(View.VISIBLE);
         FileInterfaceFactory.GetFileInterface(this, PasswordPickerFactory.GetPasswordPicker(this), fOutputFile).ReadFile(new OnResponseListener<String>() {
             @Override
             public void OnResponse(final String pass) {
                 EditPasswordActivity.this.runOnUiThread(() -> {
                     fTextEdit.setEnabled(true);
-                    fTextEdit.setText(pass);
+                    fTextEdit.setText(pass.trim());
                     if (requestFocus) {
                         fTextEdit.setSelection(pass.length());
                         fTextEdit.requestFocus();

BIN
app/src/main/res/drawable/credits_back.png


+ 23 - 0
app/src/main/res/layout/activity_credits.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ImageView
+        android:id="@+id/imageView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_alignParentTop="true"
+        android:alpha="0.65"
+        android:contentDescription="@string/_background"
+        android:scaleType="centerCrop"
+        app:srcCompat="@drawable/credits_back" />
+
+    <LinearLayout
+        android:id="@+id/credit_text_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:paddingHorizontal="10dp"></LinearLayout>
+</RelativeLayout>

+ 8 - 0
app/src/main/res/layout/activity_pass_edit.xml

@@ -9,6 +9,14 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/unencrypted_warning"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:background="@color/colorAccent"
+            android:text="@string/password_not_encrypted_wrong_default" />
+
         <android.support.v7.widget.AppCompatEditText
             android:id="@+id/password_edit"
             android:layout_width="match_parent"

+ 6 - 0
app/src/main/res/values-fr/lang.xml

@@ -82,6 +82,7 @@
     <string name="wrongPassword">Mot de passe erroné</string>
     <string name="ok">OK</string>
     <string name="are_you_sure">Êtes-vous sur.e ?</string>
+    <string name="pref_header_credits">Crédits</string>
     <string name="about_to_rm_directory">Vous allez supprimer tout les mots de passes dans le dossier</string>
     <string name="about_to_rm_file">Vous allez supprimer "%s"</string>
     <string name="conflictingFiles">Résolution des conflits</string>
@@ -129,4 +130,9 @@
     <string name="unauthorized_draw_over">Vous devez autoriser l\'affichage par dessus d\'autres applications</string>
     <string name="pref_title_system_accessibility_settings">Paramètres d\'accessibilité</string>
     <string name="pref_title_system_draw_over">Gerer l\'affichage par dessus les autres applications</string>
+    <string name="password_not_encrypted">Ce fichier n\'est pas chiffré ! Cliquez ici pour vérifier les paramètres de ce fichier</string>
+    <string name="password_not_encrypted_wrong_default">Ce fichier n\'est pas chiffré ! Cliquez ici pour vérifier vos paramètres</string>
+    <string name="credit_dev_header">Developpeur</string>
+    <string name="credit_images_header">Images</string>
+    <string name="credit_special_header">Remerciements</string>
 </resources>

+ 6 - 0
app/src/main/res/values/credit_content_style.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="CreditContentStyle" parent="AppTheme">
+        <item name="android:textColor">#222</item>
+    </style>
+</resources>

+ 8 - 0
app/src/main/res/values/credit_header_style.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="CreditHeaderStyle" parent="AppTheme">
+        <item name="android:textSize">18dp</item>
+        <item name="fontWeight">700</item>
+        <item name="android:textColor">#222</item>
+    </style>
+</resources>

+ 16 - 0
app/src/main/res/values/lang.xml

@@ -82,6 +82,7 @@
     <string name="wrongPassword">Wrong password</string>
     <string name="ok">OK</string>
     <string name="are_you_sure">Are you sure ?</string>
+    <string name="pref_header_credits">Credits</string>
     <string name="about_to_rm_directory">You are about to remove all password from this folder</string>
     <string name="about_to_rm_file">You are about to remove "%s"</string>
     <string name="conflictingFiles">Solve conflicts</string>
@@ -129,4 +130,19 @@
     <string name="unauthorized_draw_over">You must authorized \'Draw over other apps\' permission</string>
     <string name="pref_title_system_accessibility_settings">Accessibility settings</string>
     <string name="pref_title_system_draw_over">Draw over other app permissions</string>
+    <string name="password_not_encrypted">This password is not encrypted ! Click here to review file settings</string>
+    <string name="password_not_encrypted_wrong_default">This password is not encrypted ! Click here to review your settings</string>
+    <string name="credit_dev_header">Developer</string>
+    <string-array name="credit_dev_text" translatable="false">
+        <item>isundil</item>
+    </string-array>
+    <string name="credit_images_header">Images</string>
+    <string-array name="credit_images_text" translatable="false">
+        <item>Misuto</item>
+        <item>Freepik</item>
+    </string-array>
+    <string name="credit_special_header">Special thanks</string>
+    <string-array name="credit_special_text" translatable="false">
+        <item>Misuto</item>
+    </string-array>
 </resources>

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -29,4 +29,5 @@
     <integer name="id_keyboard_delete" translatable="false">-5</integer>
     <string name="id_accessibility_settings" translatable="false">id_accessibility_settings</string>
     <string name="id_draw_over_settings" translatable="false">id_draw_over_settings</string>
+    <string name="_background" translatable="false">background</string>
 </resources>

+ 4 - 3
app/src/main/res/xml/pref_headers.xml

@@ -1,7 +1,4 @@
 <preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <!-- These settings headers are only used on tablets. -->
-
     <header
         android:fragment="info.knacki.pass.settings.ui.SettingsActivity$GeneralPreferenceFragment"
         android:icon="@drawable/ic_info_black_24dp"
@@ -14,4 +11,8 @@
         android:fragment="info.knacki.pass.settings.ui.SettingsActivity$VCSPreferenceFragment"
         android:icon="@drawable/ic_info_black_24dp"
         android:title="@string/pref_header_VCS" />
+    <header
+        android:fragment="info.knacki.pass.settings.ui.SettingsActivity$CreditsFragment"
+        android:icon="@drawable/ic_info_black_24dp"
+        android:title="@string/pref_header_credits" />
 </preference-headers>

+ 1 - 1
build.gradle

@@ -7,7 +7,7 @@ buildscript {
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:4.1.3'
+        classpath 'com.android.tools.build:gradle:4.2.0'
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
     }

+ 1 - 1
gradle/wrapper/gradle-wrapper.properties

@@ -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.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip