|
|
@@ -2,8 +2,12 @@ package info.knacki.pass.io;
|
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
|
+import java.io.ByteArrayOutputStream;
|
|
|
import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
import java.util.ArrayDeque;
|
|
|
+import java.util.zip.ZipEntry;
|
|
|
+import java.util.zip.ZipOutputStream;
|
|
|
|
|
|
import info.knacki.gitdroid.callback.OnResponseListener;
|
|
|
|
|
|
@@ -50,8 +54,8 @@ public class FileMigratoryUtils {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- public static void MigratePassword(Context ctx, File from, File to, FileInterfaceFactory.PasswordGetter passInput, OnResponseListener<Void> onDone, boolean removePrevious) {
|
|
|
- MigratePassword(FileInterfaceFactory.GetFileInterface(ctx, passInput, from), FileInterfaceFactory.GetFileInterface(ctx, passInput, to), from.getAbsolutePath().equals(to.getAbsolutePath()) || !removePrevious ? onDone : new OnResponseListener<Void>() {
|
|
|
+ public static void MigratePassword(Context ctx, File from, IFileInterface to, FileInterfaceFactory.PasswordGetter passInput, OnResponseListener<Void> onDone, boolean removePrevious) {
|
|
|
+ MigratePassword(FileInterfaceFactory.GetFileInterface(ctx, passInput, from), to, !removePrevious ? onDone : new OnResponseListener<Void>() {
|
|
|
@Override
|
|
|
public void OnResponse(Void result) {
|
|
|
FileUtils.DeleteFile(from);
|
|
|
@@ -65,17 +69,27 @@ public class FileMigratoryUtils {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- public static void MigratePasswordToPassword(final Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter) {
|
|
|
+ public static void MigratePassword(Context ctx, File from, File to, FileInterfaceFactory.PasswordGetter passInput, OnResponseListener<Void> onDone, boolean removePrevious) {
|
|
|
+ MigratePassword(ctx, from, FileInterfaceFactory.GetFileInterface(ctx, passInput, to), passInput, onDone, removePrevious);
|
|
|
+ }
|
|
|
+
|
|
|
+ private interface OutputGetter {
|
|
|
+ IFileInterface GetOutput(File input);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void MigratePasswords(final Context ctx, final FileInterfaceFactory.PasswordGetter passwordGetter, final OutputGetter outputGetter, ArrayDeque<File> inputFiles, OnResponseListener<Void> onDone) {
|
|
|
final ArrayDeque<String> oldPasswords = new ArrayDeque<>();
|
|
|
- final ArrayDeque<File> oldPasswordFiles = ListPasswords(ctx, (file) -> file.getName().endsWith(PasswordFileInterface.PASSWORD_SUFFIX));
|
|
|
|
|
|
final Runnable nextFile = new Runnable() {
|
|
|
private void NextFile() {
|
|
|
- if (oldPasswordFiles.isEmpty())
|
|
|
+ if (inputFiles.isEmpty()) {
|
|
|
+ if (onDone != null)
|
|
|
+ onDone.OnResponse(null);
|
|
|
return;
|
|
|
- final File currentFile = oldPasswordFiles.poll();
|
|
|
+ }
|
|
|
+ final File currentFile = inputFiles.poll();
|
|
|
final ArrayDeque<String> currentPasswordToTry = new ArrayDeque<>(oldPasswords);
|
|
|
- MigratePassword(ctx, currentFile, currentFile, new FileInterfaceFactory.PasswordGetter() {
|
|
|
+ MigratePassword(ctx, currentFile, outputGetter.GetOutput(currentFile), new FileInterfaceFactory.PasswordGetter() {
|
|
|
@Override
|
|
|
public FileInterfaceFactory.PasswordGetter SetFile(File file) { return this; }
|
|
|
|
|
|
@@ -117,4 +131,73 @@ public class FileMigratoryUtils {
|
|
|
};
|
|
|
nextFile.run();
|
|
|
}
|
|
|
+
|
|
|
+ private static String GetFileName(Context ctx, File f) {
|
|
|
+ String rootDir = PathUtils.GetPassDir(ctx);
|
|
|
+ String absPath = f.getAbsolutePath();
|
|
|
+ return absPath.substring(rootDir.length());
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void ExportAllPasswords(final Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter, OnResponseListener<byte[]> onDone) {
|
|
|
+ // Get output password
|
|
|
+ passwordGetter.GetPassword(new FileInterfaceFactory.OnPasswordEnteredListener() {
|
|
|
+ @Override
|
|
|
+ public boolean OnResponse(String outputPassword) {
|
|
|
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
|
+ ZipOutputStream compressedStream = new ZipOutputStream(out);
|
|
|
+
|
|
|
+ MigratePasswords(ctx, passwordGetter, input -> new IFileInterface() {
|
|
|
+ @Override
|
|
|
+ public void ReadFile(OnResponseListener<String> resp) {
|
|
|
+ resp.OnError("Unsupported Operation", new UnsupportedOperationException("ReadFile"));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void WriteFile(String content, OnResponseListener<Void> resp) throws InvalidPasswordException {
|
|
|
+ try {
|
|
|
+ ZipEntry compressedFile = new ZipEntry(GetFileName(ctx, input));
|
|
|
+ compressedStream.putNextEntry(compressedFile);
|
|
|
+ PasswordFileInterface.CryptData(compressedStream, content.getBytes(), outputPassword.toCharArray());
|
|
|
+ compressedStream.closeEntry();
|
|
|
+ resp.OnResponse(null);
|
|
|
+ }
|
|
|
+ catch (Throwable e) {
|
|
|
+ resp.OnError("Failed to write to output", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String GetMethodName() {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }, ListPasswords(ctx, f -> true), new OnResponseListener<Void>() {
|
|
|
+ @Override
|
|
|
+ public void OnResponse(Void result) {
|
|
|
+ try {
|
|
|
+ compressedStream.close();
|
|
|
+ }
|
|
|
+ catch (IOException e) {
|
|
|
+ onDone.OnError("Cannot write to output", e);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ onDone.OnResponse(out.toByteArray());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void OnError(String msg, Throwable e) {
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void OnError(String msg, Throwable e) {
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void MigratePasswordToPassword(Context ctx, FileInterfaceFactory.PasswordGetter passwordGetter) {
|
|
|
+ MigratePasswords(ctx, passwordGetter, input -> FileInterfaceFactory.GetFileInterface(ctx, passwordGetter, input), ListPasswords(ctx, (file) -> file.getName().endsWith(PasswordFileInterface.PASSWORD_SUFFIX)), null);
|
|
|
+ }
|
|
|
}
|